所有文章已迁移至csdn,csdn个人主页bugpool.blog.csdn.net
本篇旨在让读者对Spring AOP实现原理有一个宏观上的认识,因此会丢失一些细节,具体实现参考:老实人Spring源码目录
阅读本篇文章前,希望读者对Spring Ioc以及Spring AOP的使用(@Aspect)由一定了解,话不多说,直接上图
准备工作
-
Service
类:有find方法跟save方法,find方法前后需要缓存操作,save方法前后需要事务操作 -
CacheableAspect
切面类:用于在Service的find方法前后进行缓存操作 -
TransctionlAspect
切面类:用于在Service的save方法进行事务操作 -
LogAspect
切面类:记录所有Controller的请求日志
AOP准备
Spring AOP自动代理时机
在service
bean的创建过程中(也就是getBean("service")
),AOP通过BeanPostProcess后置处理器操作进行介入
分为2种情况:
- 用户自定义了
targetSource
,则bean的创建(实例化、填充、初始化)均由用户负责,Spring Ioc不会在管该代理目标对象traget
,这种情况基本上不会发生,很多人用了几年Spring可能都不知道有它的存在 - 正常情况下都是Spring Ioc完成代理对象
target
的实例化、填充、初始化。然后在初始化后置处理器中进行介入,对bean
也就是service
进行代理
Spring AOP代理时机
创建代理操作wrapIfNecessary
所有的重点都在wrapIfNecessary
做了什么操作
Spring AOP创建代理
代理的方法调用
创建完代理,代理如果调用方法呢?我们以Jdk动态代理
为例子,方法的调用将会触发invoke
方法。具体源码参考Jdk动态代理 底层源码
AOP方法执行原理
Spring AOP拦截器的执行顺序
从上面可以看出,Spring AOP的代理invoke
方法,其实是拦截器
的执行。
我们先了解一下Spring AOP的执行顺序,跟栈
很像,后进先出
拦截器的执行顺序
AOP拦截器执行原理
那么这个拦截器链又如何保证before
在after
之前呢?而且还能保证find
方法的执行顺序?详情参考MethodInvocation拦截器调用原理
这部分实现原理通过几句话是解释不完的,只能给出图大家了解个大概
在这里插入图片描述
具体拦截器源码:
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 先调用before方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 继续链式调用
return mi.proceed();
}
}
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 先进行链式调用
Object retVal = mi.proceed();
// 再调用afterReturning方法
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
压轴题:Spring AOP遇上循环依赖
该部分难度系数十颗星,算是Spring源码最复杂的一块,这块弄懂可以说对Spring的理解已经达到阿里水准了。这里三言两语是不可能解释清楚的,只能贴个图,大家有个宏观上的认知,详情Spring AOP遇上循环依赖
循环依赖遇上AOP
总结
Spring AOP是Spring重要的组成部分之一,本篇只是给读者宏观上的一个认识,具体还是需要阅读源码。
画图不容易啊,麻烦各位大佬给个赞!有不懂的问题可以留言,会一一解答,有写错的地方也欢迎探讨!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述