转载

『互联网架构』插桩处理埋点(113)

上节说了javaagent和javassist,其实javassist也是基于ASM实现的。一般人不懂得JVM指令的话,根本ASM搞不起来,也用到了访问者的设计模式,看起来跟咱们写代码不是一个套路,学习成本比较高,所以有了javassist。

源码:https://github.com/limingios/netFuture/tree/master/源码/『互联网架构』插桩处理埋点(113)/

『互联网架构』插桩处理埋点(113)

(一)插桩

  • 修改上节源码,进行插桩
 IdigAgentTest 
package com.idig8;

import com.idig8.agent.test.UserServiceImpl;

import java.lang.instrument.Instrumentation;

public class IdigAgentTest {
    public static void main(String[] args) {
        System.out.println("hello world idig8!");
        UserServiceImpl userService = new UserServiceImpl();
        userService.hello();
    }
}

『互联网架构』插桩处理埋点(113)

UserServiceImpl 增加hello方法,打印方法里面的内容

package com.idig8.agent.test;

public class UserServiceImpl {
    public UserServiceImpl(){
        System.out.println("hello world!");
    }

    public void hello(){
        String p1 ="100";
        System.out.print("p1 = "+p1);

    }
}

『互联网架构』插桩处理埋点(113)

IdigAgent 增加插桩的方法

package com.idig8.agent.test;

import javassist.*;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class IdigAgent {
    public static void premain(String args, Instrumentation instrumentation) {
        System.out.println("premain:" + args);

        instrumentation.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                                    ProtectionDomain protectionDomain,
                                    byte[] classfileBuffer) throws IllegalClassFormatException {
                if (!"com/idig8/agent/test/UserServiceImpl".equals(className)) {
                    return null;
                }
                // javassist 工具 改造
                try {
                    ClassPool pool = new ClassPool();
                    pool.insertClassPath(new LoaderClassPath(loader));
                    CtClass ctclass = pool.get("com.idig8.agent.test.UserServiceImpl");
                    CtMethod method = ctclass.getDeclaredMethod("hello");
                    method.insertBefore(" System.out.println(System.currentTimeMillis());");
//                    method.insertBefore("long begin = System.currentTimeMillis();"
//                            +"       System.out.println(begin);");
//
//                    method.insertAfter(" long end = System.currentTimeMillis();n" +
//                            "        System.out.println(end - begin);");
                    return ctclass.toBytecode();
                } catch (NotFoundException e) {
                    e.printStackTrace();
                } catch (CannotCompileException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                return null;
            }
        });
    }
}

『互联网架构』插桩处理埋点(113)

pom中添加javassist的jar包

<dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.18.1-GA</version>
    </dependency>

『互联网架构』插桩处理埋点(113)

  • 代码的执行流程

    > IdigAgentTest执行这个方法

    IdigAgent ->IdigAgentTest->UserServiceImpl的类->UserServiceImpl被插桩启动开始的hello-> 打印hello方法体

premain:abc                     //IdigAgent 
hello world idig8!               //IdigAgentTest
hello world!                    //UserServiceImpl的类
1562479947074                    //UserServiceImpl被插桩启动开始的hello
p1 = 100                         //打印hello方法体

『互联网架构』插桩处理埋点(113)

  • 注意代码

    > 加入insertBefore中的bgin 和 insertAfter 的 end 通过end-begin 但是后台报错了

『互联网架构』插桩处理埋点(113)

“` java

javassist.CannotCompileException: [source error] no such field: begin

<pre><code class=""><br />>为什么呢,因为插桩的时候都是以代码快的形式,局部变量。

![](https://upload-images.jianshu.io/upload_images/11223715-f67960e6d7eaba91.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>在实际开发中不用修改原有的方法,而是会新写一个方法,在新方法进行出来,调用要插桩的方法。新方法的参数和要插桩的保持一致,包括注解,参数。其实有点类似动态代理。

“` java

public void hello$agent()

{

{

long begin = System.currentTimeMillis();

try{

hello();

}finally {

long end = System.currentTimeMillis();

System.out.println(end – begin);

}

}

}

『互联网架构』插桩处理埋点(113)

具体如何实现,后面会说

PS:还需要结合之前文章111节里面的测试类,了解如何完成插桩和埋点。

>>原创文章,欢迎转载。转载请注明:转载自,谢谢!>>原文链接地址:上一篇:

已是最新文章

原文  https://idig8.com/2019/07/17/hulianwangjiagouchazhuangchulimaidian113/
正文到此结束
Loading...