概述
字节码增强技术 有 Byte Buddy 、Javassist等多种。
- 如果是在同一个包中,没有问题,不需借助Instrumentation
- 如果是第三方包,想不修改代码的情况下实现代理技术,就可以采用Instrumentation进行引入
1. Instrumentation
什么是Instrumentation?
java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。 Java SE5中使用JVM TI替代了JVM PI和JVM DI。提供一套代理机制,支持独立于JVM应用程序之外的程序以代理的方式连接和访问JVM。java.lang.instrument是在JVM TI的基础上提供的Java版本的实现。 Instrumentation提供的主要功能是修改jvm中类的行为。 Java SE6中由两种应用Instrumentation的方式,premain(命令行)和agentmain(运行时)
premain方式 在Java SE5时代,Instrument只提供了premain一种方式,即在真正的应用程序(包含main方法的程序)main方法启动前启动一个代理程序。例如使用如下命令:
java -javaagent:agent_jar_path[=options] java_app_name
2. Javassist
ClassFileTransformer接口
一个代理实现ClassFileTransformer接口用于改变运行时的字节码(class File),这个改变发生在jvm加载这个类之前。对所有的类加载器有效。
class File这个术语定义于虚拟机规范3.1,指的是字节码的byte数组,而不是文件系统中的class文件。
接口中只有一个方法:
byte[]
transform( ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws IllegalClassFormatException;
一个示例:
public class PerformMonitorTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
}
}
ClassFileTransformer接口如何生效
ClassFileTransformer需要添加到Instrumentation实例中才能生效 。
获取Instrumentation实例的方法有2种:
- 虚拟机启动时,通过agent class的premain方法获得
- 虚拟机启动后,通过agent class的agentmain方法获得
需要在premain暴露ClassFileTransformer接口的实现类:
public class FoxAgent {
public static void premain(String args, Instrumentation instrumentation){
System.out.println("premain:获取方法调用时间");
ClassFileTransformer transformer = new PerformMonitorTransformer();
instrumentation.addTransformer(transformer);
}
}
通过这个 -javaagent:jarpath[=options] 参数,启动实际应用,就会自带agent。如果agent启动失败,jvm会终止。
3. Byte Buddy
Byte Buddy 是一个代码生成和操做库,用于在Java应用程序运行时建立和修改Java类,而无需编译器的帮助。除了Java类库附带的代码生成实用程序外,Byte Buddy还容许建立任意类,而且不限于实现用于建立运行时代理的接口。此外,Byte Buddy提供了一种方便的API,可使用Java代理或在构建过程当中手动更改类。Byte Buddy 相比其余字节码操做库有以下优点:
- 无需理解字节码格式,便可操做,简单易行的 API 能很容易操做字节码。
- 支持 Java 任何版本,库轻量,仅取决于Java字节代码解析器库ASM的访问者API,它自己不须要任何其余依赖项。
- 比起JDK动态代理、cglib、Javassist,Byte Buddy在性能上具备优点。
参考
Instrumentation与ClassFileTransformer–字节码转换工具 字节码加强技术-Byte Buddy JAVA Instrumentation
|