- pom.xml 文件。(javaagent 和 main 方法的 jar 可以分开成两个项目,单独打包 jar)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>app</artifactId>
<packaging>jar</packaging>
<version>0.1</version>
<dependencies>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<mainClass>org.example.MainApp</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifestEntries>
<Premain-Class>org.example.MyAgent</Premain-Class>
<Agent-Class>org.example.MyAgent</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 创建 premain 方法,方法的主要功能是修改 App setName() 方法体
public class MyAgent {
public static void premain(String args, Instrumentation inst) {
MyTransformer tran = new MyTransformer();
inst.addTransformer(tran);
}
}
public class MyTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if ("org/example/App".equals(className)) {
try {
// 从ClassPool获得CtClass对象
final ClassPool classPool = ClassPool.getDefault();
final CtClass clazz;
clazz = classPool.get("org.example.App");
CtMethod convertToAbbr = clazz.getDeclaredMethod("setName");
String methodBody = "{\n" +
" this.name = \"ccc\" + \" aaa\";\n" +
" }";
convertToAbbr.setBody(methodBody);
byte[] byteCode = clazz.toBytecode();
clazz.detach();
return byteCode;
} catch (NotFoundException | CannotCompileException | IOException e) {
e.printStackTrace();
}
}
System.out.println(className);
return classfileBuffer;
}
}
public class App {
private int code;
private String name;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "App{" +
"code=" + code +
", name='" + name + '\'' +
'}';
}
}
public class MainApp {
public static void main(String... args) throws Exception {
App app = new App();
app.setName("a");
app.setCode(123);
System.out.println(app);
}
}
- 启动 javaagent
java -javaagent:app-0.1-jar-with-dependencies.jar -jar app-0.1.jar
控制台输出
App{code=123, name='ccc aaa'}
name 属性被成功修改