使用javassist动态为已有的类添加方法

需求

现在有一个类Person,只有一个int age属性。
现在有一个需求,如下:
动态地为Person类新增increase方法,实现age++的效果。

javassist简介

javassist是一个用于处理java字节码的库,可以动态地修改已有的类的字节码。

javassist与jdk动态代理、cglib的比较

以下是我自己的理解,如有不对,请指正:
javassist动态地修改已有的类的字节码,不是通过生成代码,而是直接修改了类的字节码。这与jdk动态代理、cglib有本质的不同。
因为jdk动态代理是生成原始类的代理,而cglib是对方法进行拦截(gpt给出的方案是对方法进行拦截,我自己也做过实现,如果cglib场景中,Person类不去实现一个有increase方法的接口,使用反射调用的increase方法的时候,直接会报错)。

如果要通过jdk动态代理实现这个需求,则需要Person类实现一个接口,接口有increase方法,可以没有默认实现,否则jdk动态代理不能实现需求。

如果要通过cglib实现需求,则需要Person类实现一个接口,接口有默认方法increase,默认方法可以是空实现,否则cglib不能实现此需求。

javassist应用

前几天看rpc相关的文章,看到dubbo这个rpc是使用的javassist来生成接口的代理,对远程方法进行调用。
为啥dubbo使用javassist来生成带俩,而不是jdk动态代理呢?据说是因为javassis的性能更好,具体为啥更好,后面有空了,可以研究下。

代码

引入maven依赖

<dependencies>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.28.0-GA</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>compile</scope>
        </dependency>
</dependencies>

创建Person类

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Person {
    private int age;
}

测试代码

测试代码中,动态地为Person类新增increase方法,方法中将age+1。

import javassist.*;

import java.lang.reflect.Method;

public class DynamicMethodGeneratorTest {
    public static void main(String[] args) throws Exception {
        // 为Person动态添加方法
        dynamicAddMethodForPerson();

        Person person = new Person();
        // 设置age属性为20
        person.setAge(20);
        System.out.println("Before increase: " + person); // 20

        // 使用反射调用increase方法
        Method increaseMethod = person.getClass().getMethod("increase");
        increaseMethod.invoke(person);

        System.out.println("After increase: " + person); // 21
    }

    private static CtClass dynamicAddMethodForPerson() throws NotFoundException, CannotCompileException {
        ClassPool pool = ClassPool.getDefault();
        CtClass personClass = pool.get("com.qqcr.train.add_code.Person");
        // 生成一个新方法increase()
        CtMethod newMethod = CtNewMethod.make(
                "public void increase() { age++; }", // 方法的作用是为age属性+1
                personClass
        );

        // 将increase方法添加到personClass中。
        personClass.addMethod(newMethod);
        /*
        这行代码必须要调用,调用之后,添加的increase方法才会生效。
        否则new Person().getClass().getMethod("increase")会报错:NoSuchMethodException。
        我猜是因为调用了toClass,才会用这里的personClass替换元空间中的Person.class。
         */
        personClass.toClass();
        return personClass;
    }
}

测试代码最后的输出

Before increase: Person(age=20)
After increase: Person(age=21)

参考

CHATGTP-POE问答

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值