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

51次阅读

共计 1155 个字符,预计需要花费 3 分钟才能阅读完成。

前面讲到了动态代理的底层原理,接下来我们来看一下 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 方法拦截,点进方法里面可以发现代码如下:

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

正文完
 0