java 动态字节码技术javassist 动态用代码修改添加类、方法代码

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();
        }
    }
}

运行结果

在这里插入图片描述

ASM操作示范(更难)在这里插入图片描述

posted @   HumorChen99  阅读(24)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示