解析Spring AOP执行流程

Posted 小西的技术笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析Spring AOP执行流程相关的知识,希望对你有一定的参考价值。

背景

笔者在复习Spring过程中,感觉网上很多关于Spring AOP概念比较抽象。因此想在自己梳理原理的同时,用更通俗易懂的方式把他分享出来。


AOP概念

讲解AOP原理前,先通过一个实例来了解一下AOP概念。

假设我们需要完成一个会员系统,当前提供的功能有注册、登录、查找用户。需要为系统中的每个接口在接收到请求时打印请求参数,在返回结果前打印输出的结果。为此我们会定义一个切面类LogAspect。伪代码如下:

定义打印日志的切面类。

定义接口和实现类,提供登录、注册、用户查找功能。

解析Spring AOP执行流程

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。

  • 创建代理对象。

  • 调用时拦截。

解析Spring AOP执行流程

AOP入口:BeanPostProcessor

解析Spring AOP执行流程

解析Spring AOP执行流程

通过断点,找到了在执行AbstractAutowireCapableBeanFactory#initializeBean初始化对象时,调用了BeanPostProcessor#postProcessAfterInitialization,在后置处理器中为目标对象对象创建了代理。

AbstractAutoProxyCreator#wrapIfNecessary是把目标对象生成代理对象的真正的逻辑入口。该方法有两个逻辑:

  • AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean:获取该对象所有Advisors。

  • AbstractAutoProxyCreator#createProxy:为该对象创建代理对象。

解析Spring AOP执行流程

解析Spring AOP执行流程

获取当前对象的Advisors

解析Spring AOP执行流程

这个环节是对象与切面的作用范围做匹配,找出适用于当前对象的Advisors。Advisors的概念和Aspect类似,包含了Pointcut和Advice,他包含了多个Advice,每个Advice对应一条记录。

解析Spring AOP执行流程

解析Spring AOP执行流程

AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

方法是找到当前beanClass适用的Advisors。该方法逻辑如下:

  • AbstractAdvisorAutoProxyCreator#findCandidateAdvisors:获取所有Advisors。

  • AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply:对上一步获取到的所有Advisors进行过滤,仅获取当前beanClass适用的Advisors。canApply()方法使用了ClassFilter和MethodMatcher,分别根据类和方法过滤出Advisors

    解析Spring AOP执行流程

    解析Spring AOP执行流程

    解析Spring AOP执行流程

最终生成的Advisors如图:

解析Spring AOP执行流程

为当前对象创建代理

解析Spring AOP执行流程

经过上一步找到了当前对象的Advisors,接下去就是创建代理了。先初始化代理工厂,把当前对象的Advisors设置到代理工厂中。

解析Spring AOP执行流程

解析Spring AOP执行流程

解析Spring AOP执行流程

DefaultAopProxyFactory#createAopProxy:根据proxyTargetClass配置及是否是接口使用JdkDynamicAopProxy或ObjenesisCglibAopProxy来创建代理。

  • 当proxyTargetClass=true,且代理的方法有接口,此时为JDK动态代理。

  • 当proxyTargetClass=true,代理的方法没有接口,此时为CGLib代理。

  • 当proxyTargetClass=false,此时为JDK动态代理。

  • proxyTargetClass默认为false。

解析Spring AOP执行流程

创建代理时,会传入AdvisedSupport,他是代理对象的一个重要属性,维护了Advisors,TargetSource(目标对象),代理对象的接口列表,方法列表。

JdkDynamicAopProxy#getProxy:以JDK动态代理的方式创建代理。通过Proxy.newProxyInstance创建了一个目标类的实现类,就是代理类。解析Spring AOP执行流程

CglibAopProxy#getProxy:以CGLib代理方式创建代理。他是通过Enhancer生成目标类的子类,重写父类方法实现切面逻辑。

解析Spring AOP执行流程

调用时拦截

解析Spring AOP执行流程

这个过程主要有两个流程:1.获取代理对象的拦截器链,2.执行拦截器,织入切面逻辑。

无论是JDK动态代理还是CGLib代理,在触发方法调用时都会先调用AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice获取Advice拦截器链。

解析Spring AOP执行流程

JDK动态代理接口调用时序图:

解析Spring AOP执行流程

JdkDynamicAopProxy#invoke:获取到拦截器链后封装到

ReflectiveMethodInvocation

对象,递归执行proceed()。ReflectiveMethodInvocation是Joninpoint的实现类,proceed()里根据Advice选择合适的Interceptor织入逻辑,然后调用目标方法。

解析Spring AOP执行流程

CGLib代理对象接口调用时序图:

解析Spring AOP执行流程

DynamicAdvisedInterceptor#intercept:获取到拦截器链后封装到CglibMethodInvocation对象,递归执行proceed()。CglibMethodInvocation是ReflectiveMethodInvocation子类,最终CGLib同JDK代理一样,都是调用了ReflectiveMethodInvocation#proceed。

解析Spring AOP执行流程

proceeed()方法会调用MethodInterceptor#invoke往代理对象织入切面逻辑,然后调用目标对象方法。如图:

解析Spring AOP执行流程

proceed调用时序图:

解析Spring AOP执行流程


总结

AOP的流程可以概括为:bean初始化时,会去匹配当前类当前方法是否定义了Advice,获得Advisors列表,然后根据是否是接口及proxyTargetClass属性创建JDK动态代理或者CGLib代理生成代理对象。当方法被调用时,获取到所有拦截器,依次执行拦截器,把切面逻辑织入代理对象,然后再调用目标对象方法方法。



如果你喜欢本文

以上是关于解析Spring AOP执行流程的主要内容,如果未能解决你的问题,请参考以下文章

AOP执行流程

spring aop大致流程猜想

面试Spring 执行流程

Spring生命周期以及Aop的执行时机总结

Spring MVC注解Controller源码流程解析--HandlerAdapter执行流程--上

Spring AOP的理解和使用