反射_javassist demo的理解 在dubbo中的使用 减少反射开销 启动时就生成wrapper

学习于:掘金小册 《深度剖析apache dubbo 核心技术内幕》

web:Java动态字节技术之Javassist

看dubbo的时候重新看到了这东西,然后捡起一些东西来写写。

javassist是一个字节码修改工具,不需要了解字节码指令(同类型的ASM需要),性能比ASM稍差些,但是简单。操作起来跟java反射有些类似。

主要有 ClassPool ,CtClass,CtMethod,CtField,,构造器等。

顾名思义,基本可以理解是干啥的,classpool用来存储ctclass,工作方式与 JVM 类装载器非常相似。

概念啥的网上看看就差不多了,我这里也是基本层次的了解,写个demo比较好,写个复制一个类,然后修改它的方法体,然后加个属性,然后修改类名,然后调用方法的demo。

        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.20.0-GA</version>
        </dependency>
这是maven依赖。

 public static void main(String[] args) throws Exception{
        ClassPool cp = ClassPool.getDefault();
        //从池中获取全限定名的ctclass
        CtClass ct = cp.get("com.hbr.service.MyWorld");
        String name = ct.getName();
        System.out.println(name);
        String packageName = ct.getPackageName();
        System.out.println(packageName);
 
        //复制原来的类结构,创建一个新的类
        ct.setName("com.hbr.service.$MyWorld");
 
        //增加foo方法
        CtMethod ctMethod = new CtMethod(CtClass.intType,"foo",new CtClass[]{CtClass.intType,CtClass.intType},ct);
        ctMethod.setModifiers(Modifier.PUBLIC);
        ctMethod.setBody("return $1*$2;");  //$1  $2 代替形参
        ct.addMethod(ctMethod); //加入新的方法
 
        //增加一个属性
        CtField ctField = new CtField(CtClass.intType,"age",ct);
        ctField.setModifiers(Modifier.PUBLIC);
        ct.addField(ctField,"18");
 
        //写入到idea的maven的target目录下,写在其它目录可能不会加载,idea和maven的配置问题
        ct.writeFile(ClassPool.class.getClassLoader().getResource(".").getFile());
 
        //ctclass到class的转换
        Class clazz = ct.toClass();
        Object instance = clazz.newInstance();
        Method fooMethod = clazz.getMethod("foo", int.class, int.class);//这里不能使用integer.class
        Object result = fooMethod.invoke(instance, 2, 2);
        System.out.println(result);
    }
ClassPool cp = ClassPool.getDefault();

Returns the default class pool. The returned object is always identical since this method is a singleton factory.

The default class pool searches the system search path, which usually includes the platform library, extension libraries, and the search path specified by the -classpath option or the CLASSPATH environment variable.

这里注意它的搜索路径

When this method is called for the first time, the default class pool is created with the following code snippet:

ClassPool cp = new ClassPool();

cp.appendSystemPath();

这是它的替代方式

If the default class pool cannot find any class files, try ClassClassPath and LoaderClassPath.

总之就是返回一个包含了默认路径的class的class池。这个理解比较重要。

然后可以通过

cp.insertClassPath("D:codemygitdubbostudyoutyame");

这个方法设定搜索类的路径。(说实话,这个方法有点坑,特别是在maven工程中,跟target目录之类的相关)

String path=ClassPool.class.getClassLoader().getResource(".").getFile();

这个可以获取target下的class路径

CtClass ctClass2 = cp.makeClass("com.hbr.service.MyWorld");

ctClass2.writeFile(path);

这样就可以创建一个包名为com.hbr.service,类名为MyWorld的class。


这样就是单纯的没有.java文件,直接构造一个class文件,就这样


然后回到我们的demo

输入


输出:

结构是


结果增加了一个foo方法,然后反射调用了这个foo方法,然后我把class写入到了classes目录下。(其实是可以不写的) 大家可以自己尝试着操作里面的api,加深一下印象。

然后回到dubbo这里。dubbo会给每个服务提供者的实现类生产一个wrapper类,它最终调用服务提供方的接口实现类,wrapper类的存在是为了减少反射的调用。

可以查看 dubbo生成实现类的Wrapper类_Venture758的专栏-CSDN博客

重点:public class Wrapper1 extends Wrapper implements ClassGenerator.DC


反射传过来类名,方法名,参数类型和参数值。 通过类名我们可以反射获取实例,也就是上面的object,方法名直接是上面的string,参数之类的直接传递即可。

一般来说比如jdk的动态代理就是反射 method.invoke(instance,args)

而这里是invokeMethod直接调用你的这个方法,跟平常的调用没什么区别。 这里手动判断方法名,然后控制要调用的的方法,虽然生成这个类的操作没有反射操作这么简单,但是真正调用的时候,开销就比较小。 而且关键是,生成这个wrapper类的操作虽然比较麻烦,但是它是在dubbo服务启动时生成的,所以不会对运行时带来开销。

然后看看这个wrapper类的生成。


默认有两种方式,一个是JavassistProxyFactory,另一个是JdkProxyFactory。spi默认使用javassist。

看一下源码实现:


跟进去


进到ClassGenerator里面就是我们熟悉的javassist的api操作了。

然后反手看jdk那个


直接反射调用。没啥好说的。

值得注意的是上面的getproxy中的proxy,jdk的proxy是反射包的,javassist的proxy是dubbo包的,即javasist动态生成Proxy再调用newinstance。


也就是完全替代了动态代理的切面增强功能。。。定制化非常固化,适合框架使用,我们还是使用jdk的动态代理比较好,或者cglib吧。
————————————————
版权声明:本文为CSDN博主「暂时没名」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42348371/article/details/112590002

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值