【dubbo源码解析】--- 通过javassist/JavassistCompiler动态生成一个实例对象

本文对应源码地址:https://github.com/nieandsun/dubbo-study


1 问题的提出

相信对于每一个java程序员来说,早已经习惯了写一个java文件 —> 编译成class文件 —> 加载到JVM生成一个实例对象的开发流程。

但是有没有想过其实没有Java文件,也没有编译好的class文件,我们照样可以向JVM中添加一个类实例呢? —》 javassist就可以完成这种骚操作。

而且读过dubbo源码的人肯定都知道,在dubbo框架里很多地方用到了这种姿势!!!


2 javassist动态生成实例对象

注意: 当你引了dubbo的dubbo-common包后,它会自动引入javassist包,如下:
在这里插入图片描述
写一个Javassist动态生成实例对象的简单demo —》 很简单,相信每个人都可以很容易的就看懂,代码如下:

 /**
  * javassist动态生成类示例
  */
 @Test
 public void createClassObjByJavassist() throws NotFoundException, CannotCompileException,
         IllegalAccessException, InstantiationException, NoSuchMethodException,
         InvocationTargetException {

     // ClassPool:Class对象的容器
     ClassPool pool = ClassPool.getDefault();

     // 通过ClassPool生成一个public类
     CtClass ctClass = pool.makeClass("com.enjoy.service.DemoImpl");

     // 添加属性 private String name
     CtField nameFild = new CtField(pool.getCtClass("java.lang.String"), "name", ctClass);
     nameFild.setModifiers(Modifier.PRIVATE);
     ctClass.addField(nameFild);

     // 添加属性 private int age
     CtField ageField = new CtField(pool.getCtClass("int"), "age", ctClass);
     ageField.setModifiers(Modifier.PRIVATE);
     ctClass.addField(ageField);

     // 为属性name和age添加getXXX和setXXX方法
     ctClass.addMethod(CtNewMethod.getter("getName", nameFild));
     ctClass.addMethod(CtNewMethod.setter("setName", nameFild));
     ctClass.addMethod(CtNewMethod.getter("getAge", ageField));
     ctClass.addMethod(CtNewMethod.setter("setAge", ageField));

     // 添加方法  void sayHello(String name) {...}
     CtMethod ctMethod = new CtMethod(CtClass.voidType, "sayHello", new CtClass[]{}, ctClass);
     // 方法设置为PUBLIC
     ctMethod.setModifiers(Modifier.PUBLIC);
     // 方法体
     ctMethod.setBody("{\nSystem.out.println(\"hello \" + getName() + \" !!!\");\n}");
     ctClass.addMethod(ctMethod);

     //生成class类
     Class<?> clazz = ctClass.toClass();
     //创建对象
     Object obj = clazz.newInstance();
     //反射 执行方法sayHello
     obj.getClass().getMethod("setName", new Class[]{String.class})
             .invoke(obj, new Object[]{"nrsc"});
     obj.getClass().getMethod("sayHello", new Class[]{})
             .invoke(obj, new Object[]{});
 }

测试结果如下:
在这里插入图片描述


3 JavassistCompiler(dubbo对Javassist的封装)动态生成实例对象

dubbo对Javassist进行封装后搞了个JavassistCompiler对象,利用该对象可以将传入的一个字符串,直接转成java的实例对象,其使用姿势如下:

/**
 * 通过JavassistCompiler动态生成类示例
 */
@Test
public void createClassByJavassistCompiler()
        throws IllegalAccessException, InstantiationException, NoSuchMethodException,
        InvocationTargetException {
    JavassistCompiler compiler = new JavassistCompiler();

    //(1)第一个参数为一个类组成的字符串
    //(2)第二个参数为一个加载器
    //直接通过compiler方法就可以获取字符串对应的类的class类型
    Class<?> clazz = compiler.compile(
            "public class DemoImpl implements DemoService {     " +
                    "public String sayHello(String name) {" +
                    "System.out.println(\"hello \" + name);     " +
                    "return \"Hello, \" + name ;" +
                    "}}",
            this.getClass().getClassLoader());

    //通过class类型创建实例对象
    Object obj = clazz.newInstance();
    //反射 执行方法sayHello
    obj.getClass().getMethod("sayHello", new Class[]{String.class}).invoke(obj, "yoyo");
}

测试结果如下:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值