JavaAgent使用笔记

JavaAgent的原理来源这里就不多说了,有兴趣的同学请参考一下两篇文章:

  1. https://www.cnblogs.com/beautiful-code/p/6424931.html
  2. https://www.jianshu.com/p/4e34d0ab47d1

这篇文章主要时为了讲述JavaAgent在使用中的一些细节。

对JavaAgent有所了解的人都知道,JavaAgent有两种启动方式permain和agentmain分别是启动时触发和启动后嵌入,以下简称onload和attach。

探针JAR

JavaAgent程序的核心代码需要一个jar包,这个jar中必须存在一个/META-INF/MANIFEST.MF文件,文件内容如下:

Manifest-Version: 1.0
Agent-Class: com.yz.javaagent.agent.JavaAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true

注意:最后一行必须是空的

Agent-Class就是你的核心类了,代码如下:

 /**
     * attach 方式启动
     * @param args
     * @param inst
     * @throws Exception
     */
    public static void agentmain(String args, Instrumentation inst) throws Exception {
        System.out.println("args:"+args);
        String[] split = args.split(",");
        String coreJarPath = split[0];
        String className = split[1];
        String methodName = split[2];
        inst.appendToBootstrapClassLoaderSearch(new JarFile(coreJarPath));
        ClassLoader classLoader = JavaAgent.class.getClassLoader();
        Class<?> aClass1 = classLoader.loadClass("com.yz.javaagent.core.transformer.ClassUtil");
        byte[] fileByte = (byte[]) aClass1.getMethod("getClassFileByte", String.class,String.class).invoke(null, className,methodName);
        ClassDefinition classDefinition = new ClassDefinition(classLoader.loadClass(className),fileByte);
        //attach 方式时使用
        inst.redefineClasses(classDefinition);
    }

    /**
     * onload 启动前运行
     * @param args
     * @param instrumentation
     */
    public static void premain(String args,Instrumentation instrumentation) {
        //onload时使用
        instrumentation.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                return new byte[0];
            }
        });
    }

这里是参考了Arthas的源码,所以使用了classloader分离的方式,这样的好处是:不需要在目标应用中引用ASM.jar(这里用的是javassist)。

attach方式启动时进程就会触发agentmain方法,通过instrumentation.appendToBootstrapClassLoaderSearch方法将core.jar包嵌入到目标应用的classloader中,因为下边会通过反射调用里边的ClassUtil类

git:https://gitee.com/lovelyesz/javaagent.git

<configuration>
    <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
</configuration>

注意:声明package时将依赖的jar也打进去,依赖的依赖jar是打不进去的,只打入一层

这时com.yz.javaagent.core.transformer.ClassUtil这个类已经放入到了目标应用JVM的方法区了,使用反射调用getClassFileByte获得目标类的字节数组,这个自然是我们使用ASM技术修改后的了,instrumentation#redefineClasses刷新class代码。

调用Agent.jar

  • attach方式

VirtualMachine virtualMachine = VirtualMachine.attach(pid);
virtualMachine.loadAgent(agentJarPath,coreJatPath+","+args);
virtualMachine.detach();

pid:目标应用的进程ID

agentJarPath:探针jar的路径

coreJarPath:核心jar的路径

  • onload方式

java -jar demo.jar -agentlib:{agentJarPath}=k1=v1,k2=v2,k3=v3

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值