Spring AOP是怎么工作的

入口注解

首先我们来看关键注解EnableAspectJAutoProxy

该注解上有@Import(AspectJAutoProxyRegistrar.class)

该类的方法registerBeanDefinitions所做的事情是对需要被AOP起作用的bean生成新的代理bean

那么EnableAspectJAutoProxy是在哪里被使用的呢,看下面

代理方式

这里我们可以看到,springboot默认使用Cglib代理,若配置了spring.aop.proxy-target-class=false则使用Jdk动态代理,但bean没有接口时,则使用Cglib。

看下面这个例子

MyServiceImpl有接口,此时默认下MyService是Cglib

配置了spring.aop.proxy-target-class=false后是Jdk动态代理

我们再把接口去掉,配置依然是spring.aop.proxy-target-class=false

结果就使用了Cglib

准备切面

下面我们来沿着AspectJAutoProxyRegistrar 具体看一下内部实现

进入AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

这里会注册AnnotationAwareAspectJAutoProxyCreator为bean

来看一下AnnotationAwareAspectJAutoProxyCreator的继承结构

这是一个倒立的结构,可以看到它实现了接口InstantiationAwareBeanPostProcessor,该接口的方法postProcessBeforeInstantiation会在bean实例化之前执行(每个bean都会进来一次)

具体的实现在AbstractAutoProxyCreator

这里最重要的是shouldSkip,该方法实际上做了很多提前准备数据的工作

可以看到这里把数据做了本地缓存,因为这些数据后面还要使用

而这里重要的是List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);这里面会把声明了@Aspect的类进行解析

到此postProcessBeforeInstantiation的关键流程就走完了

生成代理

接下来就需要对相关的bean创建aop代理bean了,再看一下继承结构

AnnotationAwareAspectJAutoProxyCreator还有个接口是BeanPostProcessor,而这个事情就是在postProcessAfterInitialization中完成的

具体的实现还是在AbstractAutoProxyCreator

wrapIfNecessary如果允许就会生成代理

这里getProxy有Cglib和Jdk动态代理,而决定使用哪一种则是createAopProxy决定的

动态代理实现

先看JdkDynamicAopProxy的实现

很直观的就可以看到入参的InvocationHandler即是JdkDynamicAopProxy类自身

我们来看JdkDynamicAopProxy实现Object invoke(Object proxy, Method method, Object[] args)方法的关键部分

this.advised.getInterceptorsAndDynamicInterceptionAdvice方法将所有用于目标method的Advisors构建成Advice chain责任链

以下是各种Advice的封装

最后在retVal = invocation.proceed();时执行

CGLIB代理实现

再看CglibAopProxy的实现

我们来看getCallbacks的关键部分

这里的aopInterceptorDynamicAdvisedInterceptor

可以看到这里使用了与JdkDynamicAopProxy 创建chain一样的方式

总结

以上就是Spring AOP的代理创建和运行原理

如果用一张图来表示结果

更多参考

CGLIB全网详细教程 - 简书 Cglib使用

AspectJ使用_赶路人儿的博客-CSDN博客_aspectj AspectJ使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值