前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >『互联网架构』插桩处理埋点(113)

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

作者头像
IT架构圈
发布2019-07-20 20:36:38
1K0
发布2019-07-20 20:36:38
举报
文章被收录于专栏:IT架构圈IT架构圈

上节说了javaagent和javassist,其实javassist也是基于ASM实现的。一般人不懂得JVM指令的话,根本ASM搞不起来,也用到了访问者的设计模式,看起来跟咱们写代码不是一个套路,学习成本比较高,所以有了javassist。源码:https://github.com/limingios/netFuture/tree/master/源码/『互联网架构』插桩处理埋点(113)/

(一)插桩
  • 修改上节源码,进行插桩

IdigAgentTest

代码语言:javascript
复制
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();    }}

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

代码语言:javascript
复制
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);    }}

IdigAgent 增加插桩的方法

代码语言:javascript
复制
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;            }        });    }}

pom中添加javassist的jar包

代码语言:javascript
复制
  <dependency>      <groupId>org.javassist</groupId>      <artifactId>javassist</artifactId>      <version>3.18.1-GA</version>    </dependency>
  • 代码的执行流程

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

代码语言:javascript
复制
premain:abc                     //IdigAgenthello world idig8!               //IdigAgentTesthello world!                    //UserServiceImpl的类1562479947074                    //UserServiceImpl被插桩启动开始的hellop1 = 100                         //打印hello方法体
  • 注意代码

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

代码语言:javascript
复制
javassist.CannotCompileException: [source error] no such field: begin

为什么呢,因为插桩的时候都是以代码快的形式,局部变量。

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

代码语言:javascript
复制
   public void hello$agent()   {        {            long begin = System.currentTimeMillis();            try{                hello();            }finally {                long end = System.currentTimeMillis();                System.out.println(end - begin);            }        }    }

具体如何实现,后面会说

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

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-18,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 编程坑太多 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • (一)插桩
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com