自学内容网 自学内容网

Java Agent使用

https://docs.oracle.com/en/java/javase/20/docs/specs/jvmti.html

com.sun的API,如果使用其他厂商的JVM,可能没有这个API了,比如Eclipse的J9

https://www.ibm.com/docs/en/sdk-java-technology/8?topic=documentation-java-attach-api

基本使用

Java Agent提供了一种在加载字节码时对字节码进行修改的能力,有两种实现方式:

  1. 在应用启动之时,通过premain()方法来实现在应用启动时侵入
  2. 针对运行中的JVM,通过Attach API和agentmain()方法来实现侵入

premain

通过JVM参数-javaagent:*.jar启动应用。应用在启动时,会优先加载Java Agent,并执行premain()方法,这时部分的类都还没有被加载。此时,可以实现对新加载的类进行字节码修改,但如果premain()方法执行失败或者抛出异常,则JVM会被终止。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                    </manifest>
                    <manifestEntries>
                        <!--指定包含premain方法的类,需要配置为类的全路径名,必须配置-->
                        <Premain-Class>org.example.PreMainAgent</Premain-Class>
                        <!--是否可以重新定义class,默认为false,可选配置-->
                        <Can-Redefine-Classes>true</Can-Redefine-Classes>
                        <!--是否可以重新转换class,实现字节码替换,默认为false,可选配置-->
                        <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        <!--是否可以设置Native方法的前缀,默认为false,可选配置-->
                        <Can-Set-Native-Method-Prefix>true</Can-Set-Native-Method-Prefix>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

写一个入口类,注意方法名必须是premain

public class PreMainAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println(agentArgs);
    }
}

当两种方式都存在时,带有Instrumentation参数的方法的优先级更高,会被JVM优先加载

public static void premain(String agentArgs)
public static void premain(String agentArgs, Instrumentation inst)

主程序可以指定的agent的数量是没有任何限制的,但是会根据指定的先后顺序依次执行各个agent的逻辑。

使用场景

使用Idea启动项目时,可以看到启动命令加了-javaagent加载了idea_rt.jar这个agent

在这里插入图片描述

agentmain

attach模式不能通过添加启动参数的方式来连接agent和主程序,低版本的JDK需要单独引入tools.jar包,借助com.sun.tools.attach包下的VirtualMachine工具类。如果是高版本的JDK不需要引入单独引入tools.jar包。

attachmain方法只允许以下两种定义方式,当两种方式都存在时,带有Instrumentation参数的方法的优先级更高

public static void agentmain(String agentArgs)
public static void agentmain(String agentArgs, Instrumentation inst)

和premain不同的在于,需要在manifest签名文件中指定Agent-Class这个属性,可以在maven-jar-plugin像下面这样配置

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                    </manifest>
                    <manifestEntries>
                        <!--指定包含agentmain方法的类,需要配置为类的全路径名,必须配置-->
                        <Agent-Class>org.example.AgentMain</Agent-Class>
                        <!--是否可以重新定义class,默认为false,可选配置-->
                        <Can-Redefine-Classes>true</Can-Redefine-Classes>
                        <!--是否可以重新转换class,实现字节码替换,默认为false,可选配置-->
                        <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        <!--是否可以设置Native方法的前缀,默认为false,可选配置-->
                        <Can-Set-Native-Method-Prefix>true</Can-Set-Native-Method-Prefix>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

获取到VirtualMachine实例后,可以通过loadAgent方法可以实现注入agent代理类的操作,该方法的第一个参数是agent的jar路径,第二个参数是传给agnet的参数。

关于tools.jar

java8及之前tools.jar随jdk一同安装

在这里插入图片描述
java8之后,tools.jar被移除,参考JEP 220


原文地址:https://blog.csdn.net/qq_40926260/article/details/143582232

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!