java agent

一、基本概念

Java agent是在JDK1.5引入的,是一种可以动态修改Java字节码的技术。java类编译之后形成字节码被JVM执行,JVM在执行这些字节码之前获取这些字节码信息,并且对这些字节码进行修改,来完成一些额外的功能,这种就是java agent技术。

二、适用场景

  1. java agent能够在加载java字节码之前进行拦截并对字节码进行修改

  2. jvm运行期间修改已经加载的字节码

通过以上两种就可以实现在一些框架或是技术的采集点进行字节码修改,可以对应用进行监控,或是对执行指定方法或是接口时额外添加操作(打印日志、打印方法执行时间、采集方法的入参和结果等)

三、实现原理

了解java agent的实现原理就必须先了解java的类加载机制(还不了解的自行了解),这个是了解java agent的前提。

其次需要了解的是JVMTI以及JVMTIAgent,下面分别介绍下

3.1、JVMTI

JVMTIJVM Tool Interface的缩写,是JVM暴露出来给用户扩展使用的接口集合,JVMTI是基于事件驱动的,JVM每执行一定的逻辑就会调用一些事件的回调接口,这些接口可以给用户自行扩展来实现自己的逻辑

3.2、JVMTIAgent

JVMTIAgent是一个动态库,利用JVMTI暴露出来的接口实现用户自行的逻辑(eclipseidea等工具等代码调试就是通过这个实现的)

JVMTIAgent主要有三个方法:

  1. Agent_OnLoad方法,如果agent在启动时加载,就执行这个方法
    Agent_OnAttach方法,如果agent不是在启动的时候加载的,是我们先attach到目标线程上,然后对对应的目标进程发送load命令来加载
  2. agent,在加载过程中调用Agent_OnAttach函数
  3. Agent_OnUnload方法,在agent做卸载掉时候调用

3.3、instrument agent

instrument agent实现了Agent_OnLoad方法和Agent_OnAttach方法,也就是即能在启动的时候加载agent,也可以在运行期来加动态加载agent,运行期动态加载agent依赖JVMattach机制实现,通过发送load命令来加载agent

3.4、JVM Attach机制

jvm attach机制上JVM提供的一种JVM进程间通信的功能,能让一个进程传命令给另一个进程,并进行一些内部的操作,比如进行线程dump,那么就需要执行jstack进行,然后把pid等参数传递给需要dump的线程来执行,这就是一种java attach

3.5、Class Transform的实现

第一次类加载的时候要求被transform的场景,在加载类文件的时候发出ClassFileLoad事件,交给instrument agent来调用java agent里注册的ClassFileTransformer实现字节码的修改

3.6、Class Redefind的实现

类重新定义,主要用在已经被加载的类上

四、实现字节码增强的技术框架有哪些?

java agent实现字节码增强到过程:

1.修改字节码、2.加载新字节码、3.替换旧字节码

  1. Java 动态代理

Java Proxy API 通过invoke方法拦截出来相应的代码逻辑。Proxy是面向接口的,被代理的Class的所有方法调用都会通过反射调用invoke方法。

缺点:性能开销大

  1. Java 5 提供的Instrumentation API

    适应场景:适用于监控

    缺点:不适合处理灵活的代码逻辑

Instrumentation API不仅可以做字节码增强,还可以通过调用getObjectSize(Object o) 方法来计算一个对象的精确大小。

  1. ASM

ASM是一个提供字节码解析和操作的框架。CGlib 框架是基于ASM实现,而常用的框架Hibernate、Spring是基于CGlib实现AOP的。

ASM 对使用者屏蔽了整个类的字节码的长度、偏移量,能够灵活、方便地解析和操作字节码。主要提供Core APITree API

Core API 主要的类(接口):

ClassVisitor、ClassAdapter、ClassReader、ClassWriter

Tree API 主要的类(接口):

工具类:

TraceClassVisitor、CheckClassAdapter、ASMifier、Type

TraceClassVisitor 能打印ClassWriter 提供的byte[] 字节数组。

TraceClassVisitor通过初始化一个ClassWriter和一个Printer对象来打印我们需要的字节流信息。方便比较类文件及分析字节码文件的结构。

猜你喜欢

转载自blog.csdn.net/shang_xs/article/details/111432106