创建一个 java agent jar 包

发布时间 2023-11-08 10:19:21作者: iyiluo
  1. 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>
  1. 创建 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);
    }

}
  1. 启动 javaagent
java -javaagent:app-0.1-jar-with-dependencies.jar -jar app-0.1.jar

控制台输出
App{code=123, name='ccc aaa'}
name 属性被成功修改