Java Agent基本简介和使用

javaagent简介

javaagent是一种能够在不影响正常编译的情况下,修改字节码。java作为一种强类型的语言,不通过编译就不能能够进行jar包的生成。而有了javaagent技术,就可以在字节码这个层面对类和方法进行修改。同时,也可以把javaagent理解成一种代码注入的方式。但是这种注入比起spring的aop更加的优美。

javaagent主要作用

  • 可以在加载java文件之前做拦截把字节码做修改
  • 可以在运行期将已经加载的类的字节码做变更,但是这种情况下会有很多的限制,后面会详细说
    还有其他的一些小众的功能
  • 获取所有已经被加载过的类
  • 获取所有已经被初始化过了的类(执行过了clinit方法,是上面的一个子集)
  • 获取某个对象的大小
  • 将某个jar加入到bootstrapclasspath里作为高优先级被bootstrapClassloader加载
  • 将某个jar加入到classpath里供AppClassload去加载
  • 设置某些native方法的前缀,主要在查找native方法的时候做规则匹配

javaagent的使用

通过 -javaagent:xxx.jar=name=lisi&age=30 其中 xxx.jar 指定对应要加载的jar包的名字和路径,后面跟踪自己传入的参数即可
IDEA中传入参数可以参考下图


CE3544A45245B229746E496D57FF29F1.jpg

新建agent

package com.mergades.apm.javaagent;

import java.lang.instrument.Instrumentation;

/**
 * https://blog.csdn.net/fd2025/article/details/80280033
 */
public class HelloAgent {

    public static void premain(String arg, Instrumentation instrumentation) {
        System.out.println("装载成功 方法 premain 参数:" + arg);
    }
}

maven pom文件引入对应的jar包插件,指定mainfestEntries,指定自己的jar包路径

 
        
            
                org.apache.maven.plugins
                maven-jar-plugin
                2.6
                
                    
                        
                            ${project.name}
                            ${project.version}
                            com.mergades.apm.javaagent.HelloAgent
                        
                    
                    true
                
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                2.3.2
                
                    8
                    8
                    utf8
                
            
        
    

mvn install 打包

运行引入

编写单元测试

package com.mergades.apm.javaagent;


public class HelloAgentTest {
    public static void main(String[] args) {
        System.err.println("TestHelloAgent main 方法");
    }
}

单元测试run config引入自己的agent jar,直接运行,获取agent植入的输出结果。

装载成功 方法 premain 参数:name=lisi&age=30
TestHelloAgent main 方法

Agentjar和普通jar的区别

运行时jar agent
入口方法名称 Main premain
Maninfe.MF 主要参数 Main-class Premain-Class
启动参数 java -jar xxx.jar -javaagent:xxx.jar
执行顺序
是否独立启动

agent 代码植入

执行方法前加入代码,执行方法后加入代码

package com.mergades.apm.classpool;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class FirstAgent implements ClassFileTransformer {

    public final String injectedClassName = "com.mergades.apm.javaagent.HelloAgentTest";
    public final String methodName = "hello";

    @Override
    public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        className = className.replace("/", ".");
        if (className.equals(injectedClassName)) {
            CtClass ctclass;
            Long start = System.nanoTime();
            try {
                ctclass = ClassPool.getDefault().get(className);// 使用全称,用于取得字节码类<使用javassist>
                CtMethod ctmethod = ctclass.getDeclaredMethod(methodName);// 得到这方法实例
                ctmethod.insertBefore("System.out.println(11111111);");
                return ctclass.toBytecode();
            } catch (Exception e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            } finally {
                System.out.println("className  took:" + (System.nanoTime() - start));
            }
        }
        return null;

    }
}

package com.mergades.apm.javaagent;

import com.mergades.apm.classpool.FirstAgent;

import java.lang.instrument.Instrumentation;

/**
 * https://blog.csdn.net/fd2025/article/details/80280033
 */
public class HelloAgent {

    public static void premain(String arg, Instrumentation instrumentation) {
        System.out.println("premain 装载成功 方法 premain 参数:" + arg);

        // 添加Transformer
        instrumentation.addTransformer(new FirstAgent());
    }
}

单元测试

package com.mergades.apm.javaagent;


public class HelloAgentTest {
    public static void main(String[] args) {
        System.err.println("TestHelloAgent main 方法");

        hello();
    }

    public static void hello() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("HelloAgentTest hello() output");
    }

}

输出结果

premain 装载成功 方法 premain 参数:name=lisi&age=30
className  tooks:201016907
TestHelloAgent main 方法
11111111
HelloAgentTest hello() output

你可能感兴趣的:(Java Agent基本简介和使用)