java 动态字节码技术javassist
平时我们可以使用AOP来动态的操作方法的处理过程,在before、after、around、return、throw Exception等关键时机作出处理,而AOP是没办法直接修改被代理方法内部逻辑的。当有这种需求的时候就只能使用动态字节码技术来解决了。热更新代码这些其实也是通过动态字节码技术实现的。
补充说明:java动态字节码技术目前主流的是两种,一个是ASM,一个是javassist。(两种都必须在类被加载到jvm之前去修改)
ASM在创建class字节码的过程中,操纵的级别是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有一定的了解。
Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
依赖引入
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.11.0.GA</version>
</dependency>
代码
User类
/**
* 用户类
*
* @author humorchen
* @date 2021/12/29 17:05
*/
public class User {
private String username;
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
测试类
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
/**
* 动态修改方法逻辑
*
* @author humorchen
* @date 2021/12/29 17:05
*/
public class DynamicMethodTest {
public static void main(String[] args) {
//获取类池
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = null;
try {
//获取类
ctClass = classPool.getCtClass("com.example.test.method.User");
//获取方法
CtMethod getUsernameMethod = ctClass.getDeclaredMethod("getUsername");
//设置新的代码
getUsernameMethod.setBody("return \"dynamic modified your code ,old result: \" + username;");
//写入
ctClass.writeFile();
//加载该类的字节码(不能少)
ctClass.toClass();
//测试使用被修改后的类
Class userClass = ctClass.toClass();
User user = (User) userClass.newInstance();
user.setUsername("小明");
System.out.println(user.getUsername());
//换一种方法使用
User user1 = new User("小红");
System.out.println(user1.getUsername());
} catch (Exception e) {
e.printStackTrace();
}
}
}