博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式——代理模式之CGLib实现分析JDK1.8(二)
阅读量:4149 次
发布时间:2019-05-25

本文共 5370 字,大约阅读时间需要 17 分钟。

上篇博客介绍了JDK当中提供的动态代理实现方式,这篇主要是来介绍,通过CGLib工具实现的动态代理。

首先在maven项目当中添加jar包依赖

cglib
cglib
3.1

接下来我们可以直接编写具体的实现类,不需要提供接口

public class HelloServiceImpl {    public void sayHello() {        System.out.println("hello eakonzhao");    }}

接下来编写自定义的代理类,需要继承MethodInterceptor

public class HelloMethodInterceptor implements MethodInterceptor {    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {        System.out.println("Before:" + method.getName());        Object object = methodProxy.invokeSuper(o,objects);        System.out.println("After:" + method.getName());        return object;    }}

测试类

public class Client {    public static void main(String[] args) {      // 设置动态代理生成的class文件路径        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\Users\\Administrator\\Desktop\\");        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(HelloServiceImpl.class);        enhancer.setCallback(new HelloMethodInterceptor());        HelloServiceImpl helloService = (HelloServiceImpl)enhancer.create();        helloService.sayHello();    }}执行结果Before:sayHellohello eakonzhaoAfter:sayHello

我们发现这个CGLib动态代理生成了三个class文件

这个类继承了我们前面设置的HelloServiceImpl类,实现了Factory接口

我们主要看HelloServiceImpl$$EnchancerByCGLIB$$这个类,这个类当中生成了一个final的类型的sayHello方法,还有一个CGLIB$sayHello$0

public final void sayHello() {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if(this.CGLIB$CALLBACK_0 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }        if(var10000 != null) {            var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);        } else {            super.sayHello();        }    } final void CGLIB$sayHello$0() {        super.sayHello();    }

这里的this.CGLIB$CALLBACK_0就是我们传递进去的HelloMethodInterceptor对象,如果为null的话,可以看到是直接调用父类的sayHello方法,否则就调用HelloMethodInterceptor当中的intercept方法。

当我们调用自定义的HelloMethodInterceptor方法的intercept时,会执行我们添加进去的逻辑,调用MethodProxy.invokeSuper方法,来调用我们自己类的实现方法,接下来看MethodProxy当中invokeSuper的实现

public Object invokeSuper(Object obj, Object[] args) throws Throwable {        try {            this.init();            MethodProxy.FastClassInfo fci = this.fastClassInfo;            return fci.f2.invoke(fci.i2, obj, args);        } catch (InvocationTargetException var4) {            throw var4.getTargetException();        }    }

我们来看下init方法

private void init() {        if(this.fastClassInfo == null) {            Object var1 = this.initLock;            synchronized(this.initLock) {                if(this.fastClassInfo == null) {                    MethodProxy.CreateInfo ci = this.createInfo;                    MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();                    fci.f1 = helper(ci, ci.c1);                    fci.f2 = helper(ci, ci.c2);                    fci.i1 = fci.f1.getIndex(this.sig1);                    fci.i2 = fci.f2.getIndex(this.sig2);                    this.fastClassInfo = fci;                    this.createInfo = null;                }            }        }    }

这一步主要是完成对FastClassInfo的初始化操作,关于FastClassInfo,其结构如下

private static class FastClassInfo {        FastClass f1;        FastClass f2;        int i1;        int i2;        private FastClassInfo() {        }    }

f1主要保存的是代理对象的类,即HelloMethodInterceptor对象,f2是被代理对象的类信息即HelloServiceImpl,i1是代理类方法签名索引,i2是被代理类方法签名索引

FastClass的实现类就是我们上面截图当中生成的

public int getIndex(Signature var1) {        String var10000 = var1.toString();        switch(var10000.hashCode()) {        case -1725733088:            if(var10000.equals("getClass()Ljava/lang/Class;")) {                return 7;            }            break;        case -1026001249:            if(var10000.equals("wait(JI)V")) {                return 2;            }            break;        case 243996900:            if(var10000.equals("wait(J)V")) {                return 3;            }            break;        case 946854621:            if(var10000.equals("notifyAll()V")) {                return 9;            }            break;        case 1116248544:            if(var10000.equals("wait()V")) {                return 1;            }            break;        case 1535311470:            if(var10000.equals("sayHello()V")) {                return 0;            }            break;        case 1826985398:            if(var10000.equals("equals(Ljava/lang/Object;)Z")) {                return 4;            }            break;        case 1902039948:            if(var10000.equals("notify()V")) {                return 8;            }            break;        case 1913648695:            if(var10000.equals("toString()Ljava/lang/String;")) {                return 5;            }            break;        case 1984935277:            if(var10000.equals("hashCode()I")) {                return 6;            }        }        return -1;    }

生成的getIndex方法,根据方法签名的hash值来返回索引,sayHello方法返回索引为0,

在进行方法调用时,根据索引调用相应的方法。CGLib是在invoke时,会生成FastClass对象,我们在调用的时候,其实调用的是已经生成好的方法,

可以看到其实调用的被代理类的方法,即CGLIB$sayHello$0 方法,而fci.f1对象的其实是HelloServiceImpl$$EnchancerByCGLIB$$当中的 sayHello方法。

对比CGLib和JDK当中的动态代理

JDK动态代理:

1、被代理对象必须实现一个接口,而CGLib则不需要,可以是单独一个类,也可以是一个接口的实现

2、JDK动态代理生成的文件比较简单,而CGLib生成的字节码文件更复杂,

3、在方法调用上,JDK采用反射的方式进行方法调用,而CGLib是直接调用生成好的方法,执行效率更高。

 

 

 

 

你可能感兴趣的文章
HTTPS面试常问全解析,文末领取面试资料
查看>>
kotlin入门,闭关在家37天“吃透”这份345页PDF,完整PDF
查看>>
kotlin协程原理,免费Android高级工程师学习资源,威力加强版
查看>>
kotlin面试题!一口气拿了9家公司的offer,已拿offer入职
查看>>
深入解析android核心组件和应用框架,Android面试题及解析
查看>>
温故而知新!微信小程序的事件处理,吊打面试官系列!
查看>>
灵魂拷问!Android性能优化之APK优化,系列篇
查看>>
焦虑的移动互联网开发者如何破局?BAT大厂面试总结
查看>>
爆赞!Android岗大厂面试官常问的那些问题,论程序员成长的正确姿势
查看>>
爆赞!Android岗大厂面试官常问的那些问题,论程序员成长的正确姿势
查看>>
爱了爱了!Android平台HTTPS抓包解决方案及问题分析,面试必问
查看>>
爱了爱了!Android开发者值得深入思考的几个问题,送大厂面经一份!
查看>>
牛笔了!Android黑科技保活实现原理揭秘,深度好文
查看>>
牛笔了!这些面试官常问的开发面试题你都掌握好了吗?看这一篇就够了!
查看>>
看完不会的来打我!Android免打包多渠道统计如何实现?面试必会
查看>>
看完全都会了!Android开发热门前沿知识,积累总结
查看>>
看完吊打面试官!海量算法高频面试题精编解析,附带学习经验
查看>>
看完豁然开朗!一线互联网大厂面试真题系统收录!社招面试心得
查看>>
真是经典中的经典!Android开发你需要了解的那些事,深度好文
查看>>
程序员的中年危机,我想谈谈关于Android面试那些事,深度好文
查看>>