解析Spring AOP执行流程
Posted 小西的技术笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析Spring AOP执行流程相关的知识,希望对你有一定的参考价值。
背景
笔者在复习Spring过程中,感觉网上很多关于Spring AOP概念比较抽象。因此想在自己梳理原理的同时,用更通俗易懂的方式把他分享出来。
AOP概念
讲解AOP原理前,先通过一个实例来了解一下AOP概念。
假设我们需要完成一个会员系统,当前提供的功能有注册、登录、查找用户。需要为系统中的每个接口在接收到请求时打印请求参数,在返回结果前打印输出的结果。为此我们会定义一个切面类LogAspect。伪代码如下:
定义打印日志的切面类。
定义接口和实现类,提供登录、注册、用户查找功能。
Pointcut(切入点):使用@Pointcut注解以正则表达式的方式来描述切面类的作用范围。例子中定义了作用范围为:execution(* com.vey.springaop.service.*.*(..))即service包下的所有类。
Advice(通知):使用@Before,@After,@Around,@AfterReturn,@AfterThrowing,来描述什么时候执行切面逻辑以及需要执行的切面逻辑是什么,Advice相当于拦截器。例子中使用@Around会在Joinpoint前后分别执行打印入参和输出结果。
Joinpoint(连接点):由@Pointcut定义的作用范围,需要执行具体切面逻辑的方法。例子中定义的@Pointcut为service包下的所有类,该类下所有的接口都可以看做是一个Joinpoint。
Aspect(切面):对应我们定义的切面类LogAspect。他是Pointcut和Advice的合集。
Weaving(织入):把切面应用到目标对象来创建代理对象。也就是把LogAspect应用的UserServiceImpl生成代理对象,使所有接口都会执行打印日志逻辑的过程。
AOP可以拆分为三块内容:
获取对象的Advisors。
创建代理对象。
调用时拦截。
AOP入口:BeanPostProcessor
通过断点,找到了在执行AbstractAutowireCapableBeanFactory#initializeBean初始化对象时,调用了BeanPostProcessor#postProcessAfterInitialization,在后置处理器中为目标对象对象创建了代理。
AbstractAutoProxyCreator#wrapIfNecessary是把目标对象生成代理对象的真正的逻辑入口。该方法有两个逻辑:
AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean:获取该对象所有Advisors。
AbstractAutoProxyCreator#createProxy:为该对象创建代理对象。
获取当前对象的Advisors
这个环节是对象与切面的作用范围做匹配,找出适用于当前对象的Advisors。Advisors的概念和Aspect类似,包含了Pointcut和Advice,他包含了多个Advice,每个Advice对应一条记录。
AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
方法是找到当前beanClass适用的Advisors。该方法逻辑如下:
AbstractAdvisorAutoProxyCreator#findCandidateAdvisors:获取所有Advisors。
AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply:对上一步获取到的所有Advisors进行过滤,仅获取当前beanClass适用的Advisors。canApply()方法使用了ClassFilter和MethodMatcher,分别根据类和方法过滤出Advisors。
最终生成的Advisors如图:
为当前对象创建代理
经过上一步找到了当前对象的Advisors,接下去就是创建代理了。先初始化代理工厂,把当前对象的Advisors设置到代理工厂中。
DefaultAopProxyFactory#createAopProxy:根据proxyTargetClass配置及是否是接口使用JdkDynamicAopProxy或ObjenesisCglibAopProxy来创建代理。
当proxyTargetClass=true,且代理的方法有接口,此时为JDK动态代理。
当proxyTargetClass=true,代理的方法没有接口,此时为CGLib代理。
当proxyTargetClass=false,此时为JDK动态代理。
proxyTargetClass默认为false。
创建代理时,会传入AdvisedSupport,他是代理对象的一个重要属性,维护了Advisors,TargetSource(目标对象),代理对象的接口列表,方法列表。
JdkDynamicAopProxy#getProxy:以JDK动态代理的方式创建代理。通过Proxy.newProxyInstance创建了一个目标类的实现类,就是代理类。
CglibAopProxy#getProxy:以CGLib代理方式创建代理。他是通过Enhancer生成目标类的子类,重写父类方法实现切面逻辑。
调用时拦截
这个过程主要有两个流程:1.获取代理对象的拦截器链,2.执行拦截器,织入切面逻辑。
无论是JDK动态代理还是CGLib代理,在触发方法调用时都会先调用AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice获取Advice拦截器链。
JDK动态代理接口调用时序图:
JdkDynamicAopProxy#invoke:获取到拦截器链后封装到
ReflectiveMethodInvocation
对象,递归执行proceed()。ReflectiveMethodInvocation是Joninpoint的实现类,proceed()里根据Advice选择合适的Interceptor织入逻辑,然后调用目标方法。
CGLib代理对象接口调用时序图:
DynamicAdvisedInterceptor#intercept:获取到拦截器链后封装到CglibMethodInvocation对象,递归执行proceed()。CglibMethodInvocation是ReflectiveMethodInvocation子类,最终CGLib同JDK代理一样,都是调用了ReflectiveMethodInvocation#proceed。
proceeed()方法会调用MethodInterceptor#invoke往代理对象织入切面逻辑,然后调用目标对象方法。如图:
proceed调用时序图:
总结
AOP的流程可以概括为:bean初始化时,会去匹配当前类当前方法是否定义了Advice,获得Advisors列表,然后根据是否是接口及proxyTargetClass属性创建JDK动态代理或者CGLib代理生成代理对象。当方法被调用时,获取到所有拦截器,依次执行拦截器,把切面逻辑织入代理对象,然后再调用目标对象方法方法。
如果你喜欢本文
以上是关于解析Spring AOP执行流程的主要内容,如果未能解决你的问题,请参考以下文章