快速cglib替代AOP解决内部调用

上级文章:

快速Mybatis动态数据源(基于java类):https://blog.csdn.net/qq_28033719/article/details/103609120

XXL-JOB设置前规则后规则:https://blog.csdn.net/qq_28033719/article/details/103701084


问题:

spring - 4.1.2 版本,首先 spring 的 AOP 是可以开启 cglib 的代理,这意味着,AOP 原理是 cglib 的处理(具体了解 cglib 的代理写法)。

如果是没有内部调用,spring 的 AOP 会这样运行:

Spring会进入这个 CglibAopProxy 里面,调用 DynamicAdvisedInterceptor(spring自己封装的 cglib 类),然后这个类会最后这样子:

其实这里 target 就是 spring 里面存放的一个, spring 实例,并不是 cglib 给我们生成的那个 新建的 代理父类,那么一连串的调用链之后,进行调用的就是 spring 的 实例:

cglib 有个方法,是使用 mathodproxy.invokesuper(proxy, args) 这个方法如果进行内部调用的话,也可以被拦截!!

那么spring 的 cglib 会使用自己的一个封装的代理类进行处理,但是该代理类最后调用的是 springbean(spring自己的bean类)方法进行 invoke ,如果这样子,我之前做的 AOP 切面,会在内部调用的时候失效,如下图:

如果我进行一个内部调用,getPhoneOne 调用 getPhoneList 的时候,我的 AOP 是切入在 DBSource 这里的,但是,因为 Spring 的 AOP 机制,所以会导致我调用 getPhoneOne 的时候,spring 是使用 method.invoke(springbean, args) 调用 spring 的实例化类进行方法的调用, 所以,不会经过 @DBSource 的切面。

最终抛错,如下图,具体为什么会抛出错,是因为我上级文章写了动态数据源注解,会从注解获取指定相应的数据源:

那这样子,我的动态数据源注解就会失效了,如果要封装一次 Service ,然后其他service调用这个封装的 service ,也是不适合已有业务的,并且有大量的代码侵入。


解决方法:

那么就直接使用 cglib ,CGLIB 里面有个方法其实是 methodProxy.invokeSuper(o, objects)  这样子进行方法调用是可以解决内部调用的,原理是:

上图我用反射偷看了 cglib 的生成类,里面字段都是代理我给他的 SuperClass 的所有方法的代理类,所以 cglib 可以解决内部调用问题。

然后使用 BeanPostProcessor 这个是 spring bean 的初始化监控,这个 processor 其实是 spring 容器 初始化类 的 processor调用链中的一环

MySpringBeanProcessor 是我自己实现 BeanPostProcessor 的监控类。

还有个问题:

CGLIB 使用父类代理其实是,新建一个 父类,然后自己创建代理子类,那么 Spring 里面所有注入的(@Autowired @Resource)这样的属性,都会为 NULL!!

这个地方我注释掉了我自己的拷贝方法,我尝试过 BeanCopier(比较流行的HUTOOL工具包,里面有给父类复制属性的),BeanUtils,还有 cglib 自带的 BeanCopier,但全部不符合业务,hutool 的父类属性拷贝,还是会出现 null 的问题,一次 null 都不能有!所以,还是我自己基于自己业务写就好了。 


具体代码:

处理的地方 DataSourceAspect ,MySpringBeanProcessor , DBSourceEnhancerInterceptor

先把其他类也贴上来。

PhoneTradeController

package org.angular.test.controller;

import org.angular.test.model.PhoneTradeView;
import org.angular.test.service.PhoneTradeServi
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值