上篇文章主要介绍了Enhance组件的核心功能和设计思路,现在就来具体进行代码分析和实现。
主要知识点:java agent、字节码、ASM框架、Instrument
后续单独出文章介绍工具中所有使用到的技术,当前只介绍组件的实现。
流程架构:
一、invoke
Enhance组件核心方法为invoke方法,该方法由monitor组件调用。
该方法内部核心做了3件事:
1、注册字节码转换器ClassFileTransformer - EnhancerClassFileTransformer:
实现 transform方法。此函数有助于已加载类的检测。 当最初加载类或者它们是
redefined时
,可以使用ClassFileTransformer转换初始类文件字节。 此函数重新运行转换过程(无论先前是否发生过转换)。Instrumentation
简单来说在注册了ClassFileTransformer并实现了tansform后,对于class的类加载时可以触发tansform的调用,这里就可以实现我们字节码增强的核心逻辑。
源码:
2、收集jvm中入口类setServiceClass:
setServiceClass方法主要用来收集jvm中入口类,收集逻辑根据项目规范来定义,比如将某个目录下的接口类视为入口类。在ApiHelp中是将.*.DWService子类,且是接口类 视为入口类。
3、重新转换类集retransformClasses:
重新转换类集目的正式用于触发tranform方法功能。ApiHelp中在重新转换的类进行了过滤,因为对于应用来说,我们希望的监控数据结果只针对应用程序,尽可能的不要被更多不在乎的类方法所干扰。
二、字节码增强Enhance.invoke
以上就是enhance组件中核心invoke方法介绍。
另外一个核心就是字节码增强Enhance.invoke方法:
ApiHelp中字节码增强技术采用ASM中的tree API,增强工作分别为
1、前置增强
增强思路前面已经介绍过了,现在直接看增强效果:
TraceMonitorHandler.before 方法由Monitor组件实现,用于收集方法进入 开始时间和其他操作。
增强源码:
2、后置增强
增强思路前面已经介绍过了,现在直接看增强效果:
这里就比较简单了,只是记录了当前方法名称,TraceMonitorHandler.after方法由Monitor组件实现,用于收集方法进入结束时间和其他操作。
3、异常增强
增强思路前面已经介绍过了,现在直接看增强效果,注意异常增强只作用与接口类:
在入口方法中,对整个方法体进行try包装,将异常信息通过TraceMonitorHandler.methodException(var5)记录,该方法也是由Monitor组件实现。
源码:
4、SQL耗时增强
SQL耗时增强相对来说比较复杂,思路之前已经分析过了,核心就是我们需要定位到方法中对应的SQL调用代码,然后再去做增强处理,先说下效果:
需要注意的是,至于什么方法属于SQL调用,这个定义需要根据项目或者公司框架来定,或者放大范围将jdbc中的执行方法作为sql调用方,我这边没有这样做的原有是因为1、公司有对应的封装,没有必要。2、如果对jdbc层进行监控,意味着需要对整个jvm类进行增强,这样就违背了上述的一些观点(屏蔽没有必要的类方法信息)。
这里需要的实现可能需要你最少能读懂字节码指令,因为在定位方法时,需要在字节码层面中进行处理,源码如下:
后续就是比较简单了。
5、外部调用增强
如果理解了SQL增强逻辑和实现,外部调用增强就是一样的道理,直接看效果:
源码:
上述内容为Enhance组件的核心实现内容。补充一点,Enhance组件中字节码增强器所调用的方法都是属于Monitor组件方法,由于两者不属于同一个jar环境,但是都会被打入目标jvm中,需要注意的是因为要求目标程序要能请求到Monitor组件,所以在类加载时,需要注意下合理的使用类加载器(关注类加载器机制和双亲委派机制)。