前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >cglib工作原理详解

cglib工作原理详解

作者头像
johnhuster的分享
发布2022-03-29 14:38:13
4860
发布2022-03-29 14:38:13
举报
文章被收录于专栏:johnhuster

cglib是一种动态代理方式,底层通过asm产生class字节码来完成动态代理,cglib与jdk动态代理相比,除了可以代理实现接口的类也可以代理非实现接口的类,通过fastclass类来避免了java反射的使用。对jdk7以前的版本来说,jdk动态代理执行效率明显要比cglib动态代理类效率差,jdk8即以后版本对jdk动态代理进行了相应的优化,这种差距就不那么明显了。但是要代理不实现接口的类来说,cglib就是一种必要选择。

cglib代理一个类时会产生3个class文件,

上面标红部分的类就是两个相关类对应的fastclass文件,HelloServiceImpl

FastClassByCGLIB

bc82cc02.class这个文件是被代理类对应的fastclass文件,HelloServiceImpl

EnhancerByCGLIB

75d5f5ba

FastClassByCGLIB

15a4adc1.class是产生的代理类对应的fastclass文件,下面看我们经常使用的代码:

代码语言:javascript
复制
        Enhancer enh = new Enhancer();
         enh.setSuperclass(HelloServiceImpl.class);
         HelloMethodInterceptor inteceptor = new HelloMethodInterceptor();
         HelloServiceImpl hello = new HelloServiceImpl();
         inteceptor.setTarget(hello);
         enh.setCallbacks(new Callback[]{inteceptor});
 HelloServiceImpl serv = (HelloServiceImpl)enh.create();
         serv.sayHello();

上面标红部分代码产生的实例就是HelloServiceImpl

EnhancerByCGLIB

75d5f5ba.class这个类对象的实例,下面看下这个类相关部分代码:

代码语言:javascript
复制
   public final void sayHello() {       MethodInterceptor var10000 = this.CGLIBCALLBACK_0;       if (this.CGLIBCALLBACK_0 == null) {          CGLIBBIND_CALLBACKS(this);          var10000 = this.CGLIBCALLBACK_0;       }
      if (var10000 != null) {          var10000.intercept(this, CGLIBsayHello0Method, CGLIBemptyArgs, CGLIBsayHello0

上面的CALLBACK_0对应的就是HelloMethodInterceptor这个类,所以serv.sayHello()会转而调用HelloMethodInterceptor的intercept方法,下面看下HelloMethodInterceptor这个类:

代码语言:javascript
复制
public class HelloMethodInterceptor implements MethodInterceptor {
    private Object target;
 
     public HelloMethodInterceptor(Object target){
         this.target = target;
     }
 
     @Override
     public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
         System.out.println("before"+arg1.getName());
         Object res = arg3.invokeSuper(arg0, arg2);          //可以
         //Object res = arg1.invoke(target, arg2);                   //可以
         System.out.println("after"+arg1.getName());
         return res;
     }
 }

至于HelloMethodInterceptor类的intercept方法里面每个入参代表什么值可以参考产生的代理类sayHello方法,这里就不再赘述。

上面标紫色部分的代码不推荐使用,因为这样就会使用到反射,而且这种方法调用需要确保HelloMethodInterceptor类的target为被代理类而不能为创建的代理类,如果target为创建的代理类就会导致无限循环直到抛出StackOverflow异常。

至于为什么会导致循环调用呢,原因就在于:

arg1对应的是sayHello方法,但是反射调用传入的target却为代理类,根据java的多态性最终调用的还是代理类的sayHello方法。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/03/23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档