概述
spring-aop
模块是 Spring 框架中最重要的组件之一,它为我们提供了强大的 AOP 功能,并为其他扩展功能(如声明式事务、声明式异步处理等)提供了支持。在本文中,我们将深入探讨 SpringAOP 的源码,从代理对象的创建开始,揭示 SpringAOP 的运行机制。
首先,在阅读这篇文章前,请先确保对 Spring 中 Bean 创建流程有基本的了解,因为实际上这个流程也是 SpringAOP 生效的关键。在这个基础上,我们将聚焦于 SpringAOP 中的后处理器,以及与 AOP 功能密切相关的通知器、通知和切点等组件或概念,通过对这些组件的代码结构深入认知,我们将更好地理解 SpringAOP 的内部工作原理。
当我们描述 AOP 的时候,它通常包含下述概念/组件:
- 通知
Advice
:是切面逻辑的具体实现,它决定了在切点处执行什么操作; - 切点
Pointcut
:程序执行过程中的一个特定点,例如方法的调用或异常的抛出,它是通知的触发点; - 通知器
Advisor
:它代表了要对哪些对象、在哪里、应用哪些通知,它通常是且不限于是通知和切点的组合体; - 连接点
Joinpoint
:它代表了程序中的某一处位置,通常包含切点切入位置的一些信息,比如MethodInvocation
或ConstructorInvocation
; - 切面
Aspect
:它是AspectJ
的概念,在 Spring 中可以认为是一个同时包含多种Advisor
的聚合体,实际使用时,我们通过@Aspect
注解声明的切面中的方法会被转为多个Advisor
;
接下来,我们将围绕着上述内容,展开研究。
本专题共三篇文章,这是第一篇:
- 深入理解 SpringAOP(一):AOP 组件概述;
- 深入理解 SpringAOP(二):AOP的执行流程;
- 深入理解 SpringAOP(三):AspectJ支持;
一、通知器
因此,某种程度上来说,Advisor
就是某个具体切入规则的最小单位。
1、实现体系
通知器 Advisor
本身的方法异常简单,它只规定“要在哪里应用哪些通知”,而“对哪些类使用”则交由子类来实现:
public interface Advisor {
// 获取通知操作,即具体的操作逻辑
Advice getAdvice();
// 每个切入目标是否都需要一个新的通知器
boolean isPerInstance();
}
因此一般 Advisor
不会直接使用,而是转为具体的 PointcutAdvisor
和 IntroductionAdvisor
使用。
2、切点通知器
PointcutAdvisor
,直译即切点通知器,允许通知器提供一个切点类 Pointcut
,用于匹配特定的方法或者类:
public interface PointcutAdvisor extends Advisor {
// 获取切点,即类或方法匹配器
Pointcut getPointcut();
}
它也是最常见的通知器,Spring 中大部分我们熟知的功能都基于它实现,比如用于处理 @Async
注解的 AsyncAnnotationAdvisor
,与用于处理 @Transcational
注解的 TransactionAttributeSourceAdvisor
(严格来说这么说并不准确,因为实际上注解是由 TransactionAnnotationParser
处理的,不过这里我们认为它们相关)。
3、引介入通知器
IntroductionAdvisor
,直译即为引介通知器,比较少用到的通知器,用于实现接口引入——即让一个 bean 无中生有的获得特定某些接口的方法,有点类似于 kotlin 的扩展函数:
public interface IntroductionInfo {
// 需要引入的接口,即被切入的类等于变相的实现了这些接口
Class<?>[] getInterfaces();
}
它比较常用的实现应该是 DeclareParentsAdvisor
,用于配合 AspectJ
的 @DeclareParents
做接口引入,不过确实不太常见,因此我们了解即可。
二、通知
Advice
即 “通知”,它表示切入对象后,需要“在什么地方做什么事”。它的子接口非常多,但是按切入位置可以简单分为三类:
- 执行前通知:
BeforeAdvice
; - 环绕通知:
InterceptorAdvice
; - 后置通知:
AfterAdvice
,这里又分为返回后通知AfterReturningAdvice
和异常通知ThrowsAdvice
;
比较有趣的是,除了 DynamicIntroductionAdvice
外,Advice
、Interceptor
、BeforeAdvice
和 AfterAdvice
这几个顶级接口都是没有抽象方法的标记接口,因此我们可以一般只关注具体的实现接口即可。
方法拦截器与切点
方法拦截器 MethodInterceptor
最常见的 Advice
,我们熟知的绝大部分基于 SpringAOP 提供的功能都依赖它实现——实际上,就算是其他的实现,到最后执行代理方法的时候依然要适配为 MethodInterceptor
去执行。
public interface MethodInterceptor extends Interceptor {
// 拦截方法调用
@Nullable
Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;
}
在这里,我们就会接触到 Joinpoint
,也就是切点的概念,MethodInvocation
就是方法切点:
它包含了一次方法调用中的一些已知信息,包括调用的方法、调用的参数等等,最常见的实现是 ReflectiveInvocation
,我们在 AspectJ
中接触的 JoinPoint
跟它基本一样。
三、切点
切面 Pointcut
是属于 PointcutAdvisor
的一个组件,它用于匹配类或者方法:
public interface PointcutAdvisor extends Advisor {
/**
* Get the Pointcut that drives this advisor.
*/
Pointcut getPointcut();
}
切点由类型过滤器 ClassFilter
和方法匹配器 MethodMatcher
两个组件共同组成:
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher();
}
当使用时,将仅会拦截 ClassFilter
不过滤的类中与 MethodMatcher
匹配的方法。
比较常用的实现类为支持对类和方法名进行表达式匹配的 NameMatchMethodPointcut
,与支持 Spring 元注解机制,能够按照类和方法上注解进行匹配的 AnnotationMatchingPointcut
。
四、后处理器
AOP 发生在 Bean 的创建过程中,它基于特定的后处理器 AbstractAutoProxyCreator
完成,当然,实际上它的背后是一个大家族:
两个关键的抽象类:
AbstractAutoProxyCreator
:AbstractAutoProxyCreator
是一个抽象类,实现了BeanPostProcessor
接口,用于自动创建代理对象。它的作用是在Spring容器中自动检测符合条件的bean,并对其进行代理。它可以根据一些配置条件(例如bean的名称、类型、注解等)决定是否对目标bean进行代理,并提供了一些钩子方法供子类实现自定义的代理逻辑;AbstractAdvisorAutoProxyCreator
:AbstractAdvisorAutoProxyCreator
是AbstractAutoProxyCreator
的子类,它进一步扩展了自动代理的功能。除了AbstractAutoProxyCreator
的功能外,AbstractAdvisorAutoProxyCreator
还能够通过配置Advisor(通知器)来决定代理的行为;
两个关键的实现类:
AspectJAwareAdvisorAutoProxyCreator
:AspectJAwareAdvisorAutoProxyCreator
继承自AbstractAdvisorAutoProxyCreator
,它是Spring AOP的一个关键组件之一,用于实现基于AspectJ注解的自动代理。它支持使用AspectJ注解(如@Aspect
、@Pointcut
、@Before
、@After
等)来定义切面,然后根据这些切面的定义,在目标 bean 上应用相应的通知;AnnotationAwareAspectJAutoProxyCreator
:AnnotationAwareAspectJAutoProxyCreator
是AspectJAwareAdvisorAutoProxyCreator
的子类,它进一步扩展了 AspectJ 注解的自动代理功能。与AspectJAwareAdvisorAutoProxyCreator
相比,AnnotationAwareAspectJAutoProxyCreator
提供了更加灵活的注解驱动的 AOP 配置方式。它支持使用@Aspect
注解定义切面,并且还支持其他注解如@Before
、@After
、@Around
等,用于在目标 bean 的方法上应用切面逻辑;
默认情况下,我们的项目都是基于 AnnotationAwareAspectJAutoProxyCreator
实现的 AOP 功能。
在后文,我们会深入后处理器的源码,从而跟踪 AOP 的运行流程。