吃透动态代理,解密spring AOP源码(四)

生如蚁美如神 2019-07-01

前面讲到了动态代理的底层原理,接下来我们来看一下aop的动态代理.
Spring AOP使用了两种代理机制:一种是基于JDK的动态代理,一种是基于CGLib的动态代理.

①JDK动态代理:使用JDK创建代理有一个限制,它只能为接口创建代理实例.这一点可以从Proxy的接口方法
newProxyInstance(ClassLoader loader,Class [] interfaces,InvocarionHandler h)中看的很清楚
第二个入参 interfaces就是需要代理实例实现的接口列表.
②CGLib:采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用
并顺势织入横切逻辑.
③对比:CGLib所创建的动态代理对象的性能比JDK的高大概10倍,但CGLib在创建代理对象的时间比JDK大概多8倍,所以对于singleton的代理对象或者具有实例池的代理,因为无需重复的创建代理对象,所以比较适合CGLib动态代理技术,反之选择JDK代理。值得一提的是由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中final的方法进行代理。

但是这种实现方式存在三个明显需要改进的地方:

a.目标类的所有方法都添加了横切逻辑,而有时,这并不是我们所期望的,我们可能只希望对业务类中的某些特定的方法添加横切逻辑;

b.我们通过硬编码的方式制定了织入横切逻辑的织入点,即在目标业务方法的开始和结束前织入代码

c.我们手工编写代理实例的创建过程,为不同类创建代理时,需要分别编写相应的创建代码,无法做到通用;

还有一个问题是:spring依赖注入时,什么时候会创建代理类,有时候是cglib有时候是jdkproxy有时候只是普通实例,有兴趣的可以查阅资料,getBean依赖注入过程,可查看IOC源码。

下面我们举个例子看看aop事务注解是怎么实现的。
JDK动态代理:aop中生成的代理类是JdkDynamicAopProxy子类,debug调试的时候可以看到,打开源码可看到实现了AopProxy和invocationHandler也就实现invoke方法。
invoke关键代码:

// Get the interception chain for this method.加载一系列的拦截器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

TransactionInterceptor是事务拦截器,所有带有@Transactional注解的方法都会经过拦截器invoke方法拦截,点进方法里面可以发现代码如下:

吃透动态代理,解密spring AOP源码(四)

比如回滚方法点进去发现是获取事务管理器然后回滚

吃透动态代理,解密spring AOP源码(四)

最后看下静态代理,JDK动态代理及cglib动态代理的对比

吃透动态代理,解密spring AOP源码(四)

相关推荐