浅谈CglibJdk以及ProxyFactory实现动态代理上的区别
Posted 默辨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈CglibJdk以及ProxyFactory实现动态代理上的区别相关的知识,希望对你有一定的参考价值。
动态代理就是在不改变原代码逻辑的基础上,对代码功能进行增强。
一、Jdk动态代理
Jdk的动态代理是基于接口的,即如果想要对目标对象进行增强,目标对象一定要实现某一个接口,因为传入的参数就是接口。
在Spring与MyBatis的整合过程中,就是使用jdk的动态代理,对Mapper文件进行代理,最终成为Spring中的Bean对象。
1、新增一个UserService接口
![](https://image.cha138.com/20211031/7d48ab7cd3c0409b83c70651662e7f55.jpg)
2、新增一个接口的实现类UserrServiceImpl
![](https://image.cha138.com/20211031/34a0a837c0394166bdd6a2f39b9a56de.jpg)
3、编写Jdk动态代理测试类
![](https://image.cha138.com/20211031/f2bbc2c3767d46d0b422296080a9ce74.jpg)
测试结果:
![](https://image.cha138.com/20211031/2e893cdb8c2c474986b1d0f60bd3560d.jpg)
二、Cglib动态代理
Cglib接触比较少,但他也是一种实现动态代理的方式,使用该方式进行功能增强的时候,被代理的对象不需要实现接口,可以简单的理解为要求更低。
1、对之前的UserServiceImpl类进行改造
![](https://image.cha138.com/20211031/130a2d63a22845b1bb179329138da9ee.jpg)
2、编写对应的Cglib测试代码
![](https://image.cha138.com/20211031/f921300c48ca4c5aad9cb8868d7b06c2.jpg)
测试结果:
![](https://image.cha138.com/20211031/c324c8eb61074fd4ba095c6385ccb6d3.jpg)
补充:
3、对同一个类的不同方法使用不同的代理方法
对该cglib代理测试方法进行改造。使得我们在调用show方法时,触发对应的增强功能;使用test方法的时候,不进行任何的增强操作。
setCallbacks方法内编写方法的代理逻辑
setCallbackFilter方法内编写被代理对象的方法过滤逻辑
![](https://image.cha138.com/20211031/720097fe12ea48db8eed7a117bc2d207.jpg)
测试结果:
![](https://image.cha138.com/20211031/c98fdb692b8d40fbb3cb6af991cc0e8c.jpg)
三、ProxyFactory动态代理
前面介绍了两种不同的实现动态代理的方式。在Spring的动态代理中,同样支持上面的两种不同形式的动态代理,Spring会根据代理对象的不同条件,选择使用不同的实现动态代理的方式。
![](https://image.cha138.com/20211031/d01a8758378f4774a2c1c1ce9950a09f.jpg)
试问,如果让你实现一个功能,如何让两个不同的操作,变得统一?
你可以试着想一想Spring是如何使用xml形式、@Bean形式、@Component形式定义Bean的。没错,就是定义一个中间态,即BeanDefinition。
Spring这里也有同样的设计,它将两个不同的对象操作集中到一个ProxyFactory对象上,最终使用ProxyFactory对象来执行对应的动态代理操作。
Spring中的AOP就是使用ProxyFactory来实现的,所以下面的测试代码,我也仿造AOP部分的代码进行测试
1、编写对应的Before方法
![](https://image.cha138.com/20211031/45bd0fa721c44c7d9fb76c101c4f8266.jpg)
2、编写对应的After方法
![](https://image.cha138.com/20211031/c5e0a708d5ec4f91a2ac63110b92931b.jpg)
3、编写对应的Throws方法
![](https://image.cha138.com/20211031/0236ce316988419282487b93af8b367f.jpg)
4、编写对应的测试方法
如果在advice中不添加MethodInterceptor对象,那么就会使用默认的逻辑,即仅完成show方法的调用。
即此处展示的代码MethodInterceptor部分的代码可以省略,然后将代理逻辑都封装到advice实现类中即可。
![](https://image.cha138.com/20211031/e30a32580bc846b8a1e055c506fb58ab.jpg)
观察测试代码,我们可以发现,使用factory.getProxy()获取的结果再强转为UserService后是一个null,一个null依然能够调用show方法,由此可见此时是使用代理对象进行方法调用的,通过旁边的调试框我们也不难发现使用的是Cglib代理方法生成了代理对象。
即如果我们想要执行方法后的对象,只需要在return的时候,返回我们的proceed对象就好了。
![](https://image.cha138.com/20211031/2a9199125cc14b1880cd9a87954c4f9a.jpg)
5、高级版本,更细粒度的代理
通过观察addAdvice方法的底层我们可以发现,我们添加的addvice对象,最终都会封装为advisor对象
![](https://image.cha138.com/20211031/fb9a4f187a844700a2a7fc8a2ed8302b.jpg)
测试代码:
Advice + Pointcut = Advisor
Pointcut:何种条件才能满足切入点条件,即何种条件才进行Advice的代理逻辑
Advice:对应的代理逻辑
理解使用该种方式定义Advisor,对于Spring中AOP源码部分理解起着至关重要的作用!!!
![](https://image.cha138.com/20211031/29b4dfab50384deeb67e8c9f4cc91f62.jpg)
测试结果:
MoBeforeAdvice是默认添加的代理逻辑,所以两个方法都会进行调用
MoAfterAdvice只有当调用的方法为test的时候才进行调用
![](https://image.cha138.com/20211031/073000fb02144bc59c4b8a0896a87d23.jpg)
四、Spring中AOP源代码分享
Spring的AOP就是通过ProxyFactory进行实现的,通过观察上面的内容我们不难发现,想要完成对一个方法的代理,大致需要以下一个步骤即可:
1. 找到符合当前Bean的所有的Advice
2. 将所有的Advice添加到ProxyFactory的对象中
3. 调用对应的方法
其实AOP就这么简单,详细的AOP源码分析可以参考:xxxx
此处仅展示部分源代码截图:
1、AOP方法的代理入口
![](https://image.cha138.com/20211031/d0f9d31480ea46f0a646d9c697a217b9.jpg)
2、找到当前Bean的所有Advice
![](https://image.cha138.com/20211031/9f940e7128b14b55aa74823c088209d1.jpg)
3、找到符合当前Bean的所有的Advice
![](https://image.cha138.com/20211031/fd0ec82c0f264f288ec7639149c17c9f.jpg)
4、将所有的advisor对象添加ProxyFactory的对象中
![](https://image.cha138.com/20211031/11199692b40549ddb1acd8c3613e2d24.jpg)
5、获得对应的Advisor责任链并调用入口
![](https://image.cha138.com/20211031/fcc0d591bb9a47bead1a443663ba2731.jpg)
6、最终的调用方法位置
![](https://image.cha138.com/20211031/3fe7d22994ac4044a6d523b63cc2ab90.jpg)
以上是关于浅谈CglibJdk以及ProxyFactory实现动态代理上的区别的主要内容,如果未能解决你的问题,请参考以下文章
Spring读源码系列之AOP--04---proxyFactory创建代理对象
dubbo源码阅读-ProxyFactory之StubProxyFactoryWrapper本地存根
#yyds干货盘点# 老王读Spring AOP-4Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析