javaagent

       如果是第三方包,想不修改代码的情况下实现代理技术,就可以采用Instrumentation进行引入;什么是Instrumentation?

    Java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。Instrumentation提供的主要功能是修改jvm中类的行为。 Java SE6中由两种应用Instrumentation的方式,premain(命令行)和agentmain(运行时)

ClassFileTransformer接口

  一个代理实现ClassFileTransformer接口用于改变运行时的字节码(class File),这个改变发生在jvm加载这个类之前。对所有的类加载器有效。

byte[]
    transform(  ClassLoader         loader,
                String              className,
                Class<?>            classBeingRedefined,
                ProtectionDomain    protectionDomain,
                byte[]              classfileBuffer)
        throws IllegalClassFormatException;

  ClassFileTransformer需要添加到Instrumentation实例中才能生效。

      Javaagent是java命令一个参数。参数 javaagent 用于指定一个 jar 包并且对该 java 包有2个要求:

      1、这个 jar 包的 MANIFEST.MF 文件必须指定 Premain-Class 项。

      2、Premain-Class 指定的那个类必须实现 premain() 方法。

      premain 方法,就是运行在 main 函数之前的类。当Java 虚拟机启动时,在执行 main 函数之前,JVM 会先运行-javaagent所指定 jar 包内 Premain-Class 这个类的 premain 方法 ,并且对premain方法的签名也有要求,签名必须满足以下两种格式:

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

       JVM 会优先加载 带 Instrumentation 签名的方法,加载成功忽略第二种,如果第一种没有,则加载第二种方法。这个逻辑在sun.instrument.InstrumentationImpl 类中:

  

      使用 javaagent 需要几个步骤:

  1. 定义一个 MANIFEST.MF 文件,必须包含 Premain-Class 选项,通常会加入Can-Redefine-Classes 和 Can-Retransform-Classes 选项。
  2. 创建一个Premain-Class 指定的类,类中包含 premain 方法,方法逻辑由用户自己确定。
  3. 将 premain 的类和 MANIFEST.MF 文件打成 jar 包。
  4. 使用参数 -javaagent: jar包路径 启动要代理的方法。

    创建类包含PreMainTraceAgent

       

public class PreMainTraceAgent {

    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("agentArgs:" + agentArgs);
        inst.addTransformer(new DefineTransformer(), true);
    }

    static class DefineTransformer implements ClassFileTransformer {

        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                                ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
            System.out.println("remain load class:" + className);
            return classfileBuffer;
        }
    }

}

  使用maven插件添加MANIFREST.MF文件

<plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.1.0</version>
                    <configuration>
                        <archive>
                            <!--自动添加META-INF/MANIFEST.MF -->
                            <manifest>
                                <addClasspath>true</addClasspath>
                            </manifest>
                            <manifestEntries>
                                <Premain-Class>com.smile.PreMainTraceAgent</Premain-Class>
                                <Agent-Class>com.smile.PreMainTraceAgent</Agent-Class>
                                <Can-Redefine-Classes>true</Can-Redefine-Classes>
                                <Can-Retransform-Classes>true</Can-Retransform-Classes>
                            </manifestEntries>
                        </archive>
                    </configuration>
                </plugin>
Premain-Class :包含 premain 方法的类(类的全路径名)
Agent-Class :包含 agentmain 方法的类(类的全路径名)
Boot-Class-Path :设置引导类加载器搜索的路径列表。查找类的特定于平台的机制失败后,引导类加载器会搜索这些路径。按列出的顺序搜索路径。
列表中的路径由一个或多个空格分开。路径使用分层 URI 的路径组件语法。如果该路径以斜杠字符(“/”)开头,则为绝对路径,否则为相对路径。
相对路径根据代理 JAR 文件的绝对路径解析。忽略格式不正确的路径和不存在的路径。如果代理是在 VM 启动之后某一时刻启动的,则忽略不表示 JAR 文件的路径。(可选) Can
-Redefine-Classes :true表示能重定义此代理所需的类,默认值为 false(可选) Can-Retransform-Classes :true 表示能重转换此代理所需的类,默认值为 false (可选) Can-Set-Native-Method-Prefix: true表示能设置此代理所需的本机方法前缀,默认值为 false(可选)

      重新开一个工程,只需要写一个带 main 方法的类即可:

public class App {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Hello World!");
        TimeUnit.SECONDS.sleep(3);
        System.out.println("main end");
    }
}

     添加vm参数

-javaagent:D:/workspace/javaagent-demo-1.0-SNAPSHOT.jar

  

      

posted on 2022-11-05 18:55  溪水静幽  阅读(262)  评论(0)    收藏  举报