1、字节码简述
2、字节码增强
2.1、ASM
ASM可以直接生成字节码文件,也可以动态修改字节码文件,Spring的AOP的cglib就是基于ASM实现的。
由于字节码的格式是固定的,所以ASM可以根据字节码数据结构读取对应位置的数据,然后再修改对应位置的数据即可。
ASM框架涉及的方法都和字节码指令级相关,因此对于指令不熟悉的话很难适应ASM框架。所以最好是有直接基于Java编码的方式对字节码文件进行修改,对于字节码文件的内容进行抽象,javasisst框架就是很好的选择。
2.2、javasisst
javasisst进行字节码增强时,使用者无需关心字节码的结构和指令语法,分别采用ctClass、ctMethod、ctField对类、方法和属性进行抽象,分别调用对应的方法即可完成字节码增强逻辑。
如针对方法进行增强,那么简单增强逻辑代码如下案例:
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import java.io.IOException;
public class AssistTest {
public static void main(String[] args) {
try {
CtClass ctClass = ClassPool.getDefault().getCtClass("javaassist.User");
CtMethod ctMethod = ctClass.getDeclaredMethod("change");
ctMethod.insertBefore("System.out.println(\"javaassist\");");
ctMethod.insertAfter("System.out.println(\"end\");");
//Class clazz = ctClass.toClass();
ctClass.writeFile("javaassist.User");
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
javaassist生成之后的class文件如下:
逻辑比较简单先根据全路径类名获取CtClass对象,然后根据方法名获取CtMethod对象,在调用对应的插入逻辑方法分别在对应方法前后插入增强逻辑,最好在调用CtClass的写入文件方法将当前类逻辑写入文件生成字节码文件。
2.3、动态字节码增强
ASM和Javasisst都可以创建字节码文件和修改字节码文件,对应的目标都是字节码文件。也就是说在JVM加载字节码文件之前就需要对字节码文件进行修改,而一旦JVM类加载器将目标类加载了,然后此时就无法通过修改字节码文件的方式来实现动态的字节码增强了。
所以如果想要在JVM加载字节码文件之后还进行字节码增强,就需要适应到JDK提供的Instrument。Instrument通常可以配合Javaagent一块使用。
3、Javaagent
Javaagent相当于一个插件,在JVM启动的时候可以添加 javaagent配置指定启动之前需要启动的agent jar包这个agent包中需要有MANIFEST.MF文件必须指定Premain-Class配置,且Premain-Class配置指定的Class必须实现premain()方法
在JVM启动的时候,会从agent包中找到MAINIFEST.MF中配置的Class,执行其实现的premain方法,而且这一步是在main方法之前执行的。这样就可以在JVM启动执行main方法之前做一些其他而外的操作了。
参考:
基于Javaagent技术实现字节码增强及Instrumentation接口详解 - Lucky帅小武 - 博客园