一、三大核心概念:各司其职的三角支架
1. Pointcut —— "在哪里"
Pointcut,中文译为切点,它回答的是一个根本性问题:哪些连接点需要被增强?
连接点(JoinPoint)是程序执行过程中所有可被拦截的点,比如方法调用、方法执行、异常抛出等。而 Pointcut 本质上是一个谓语表达式,它从无数连接点中筛选出符合条件的子集。
Spring 提供了多种 Pointcut 实现方式:通过方法名精确匹配的 NameMatchMethodPointcut、通过正则表达式筛选的 JdkRegexpMethodPointcut、基于 AspectJ 表达式的 AspectJExpressionPointcut、根据事务注解判断的 TransactionAttributeSourcePointcut,以及支持 JSR107 缓存注解的 AnnotationJCacheOperationSource 等。这些实现共同构成了 Pointcut 的武器库,让开发者可以根据方法签名、注解、类类型等维度灵活定义拦截规则。
从接口结构上看,Pointcut 包含两个核心子接口:ClassFilter 负责判断哪些类需要被拦截,MethodMatcher 负责判断哪些方法需要被拦截。二者通过 matches 方法完成匹配逻辑。
一句话概括:Pointcut 是"目标地点",它决定了切面逻辑的作用范围。
2. Advice —— "做什么"
Advice,中文译为通知,它回答的是另一个根本性问题:在连接点上执行什么操作?
Advice 是横切逻辑的实际载体。它定义了在目标方法执行之前、之后、环绕等不同时机插入的具体行为。根据执行时机的不同,Spring AOP 将 Advice 分为以下几种类型:
- 前置通知(Before Advice):在目标方法执行之前运行,如记录方法开始时间。
- 后置通知(After Returning Advice):在目标方法正常返回后运行,如记录返回值。
- 异常通知(After Throwing Advice):在目标方法抛出异常时运行,如异常告警。
- 最终通知(After Advice):无论目标方法是否异常,最终都会执行,如资源清理。
- 环绕通知(Around Advice):包围目标方法的执行,可以在前后插入逻辑,甚至决定是否执行目标方法,功能最为灵活。
从接口体系上看,Advice 是 AOP 联盟定义的顶层接口,本身是一个标识接口,不包含任何方法。它的子接口如 MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice、AroundAdvice 等,才是真正承载逻辑的实现者。而在 Spring 内部,所有 Advice 最终都会被适配为 MethodInterceptor,这是代理对象执行拦截链时真正调用的接口。
一句话概括:Advice 是"任务内容",它定义了到达目标地点后要执行的具体动作。
3. Advisor —— "在哪做 + 做什么"
Advisor,中文译为适配器或通知器,它是 Pointcut 和 Advice 的组合体。如果说 Pointcut 是地图上的坐标,Advice 是行动指令,那么 Advisor 就是一份完整的作战计划——既标注了行动地点,又明确了行动内容。
Advisor 作为 Spring AOP 的核心接口,其定义非常简洁:它同时持有一个 Pointcut 和一个 Advice。当 Spring 容器在创建 Bean 时判断某个 Bean 需要生成代理,就会收集所有匹配的 Advisor,将它们组装成拦截器链,最终织入代理对象。
Spring 提供了多种 Advisor 实现,其中最常用的是 DefaultPointcutAdvisor,它允许开发者分别设置 Pointcut 和 Advice。另一种是 NameMatchMethodPointcutAdvisor,通过方法名直接匹配。此外还有 IntroductionAdvisor 等特殊类型。
一句话概括:Advisor 是"完整作战计划",是 Spring AOP 中描述一个切面的最小完整单元。
二、关系模型图解:从分离到聚合
理解了三个概念各自的职责后,我们来看它们如何组装成完整的关系模型。
关系一:Advisor = Pointcut + Advice
这是整个模型的基石。用一个公式来表达:
Advisor(适配器) = Pointcut(切点) + Advice(通知)
Pointcut 单独存在时,只知道"要拦截哪些方法",但不知道"拦截后干什么"。Advice 单独存在时,只知道"要执行什么逻辑",但不知道"在哪里执行"。只有二者结合为 Advisor,才构成一个可被 Spring 识别和使用的完整切面描述。
这就好比:你有一把钥匙(Pointcut),也有一把锁(Advice),但只有把钥匙插进锁里(组合为 Advisor),门才能被打开。
关系二:ProxyFactory 是组装工厂
如果说 Advisor 是零件,那么 ProxyFactory 就是组装工厂。它负责将目标对象(Target)与一个或多个 Advisor 组合,生成最终的 AOP 代理对象。
组装过程分为几个关键步骤:
第一步:扫描并收集 Advisor。 Spring 容器启动时,通过 BeanPostProcessor(如 AnnotationAwareAspectJAutoProxyCreator)扫描所有被 @Aspect 标记的切面类,提取其中的切点表达式和通知注解,生成对应的 Advisor 对象。同时,容器也会收集项目中自定义的 Advisor 实现,以及内置的事务 Advisor、缓存 Advisor 等。
第二步:加入框架级 Advisor。 Spring 会自动向 Advisor 集合最前面加入一个特殊的 DefaultPointcutAdvisor,其 Advice 是 ExposeInvocationInterceptor,作用是在调用代理对象方法时将相关信息存入 ThreadLocal,以便在多个 Advisor 之间传递上下文。
第三步:加入自定义 MethodInterceptor。 经过前两步后,Spring 会将自定义的 MethodInterceptor 实现类也包装为 Advisor,放入集合最前面,确保自定义逻辑优先执行。
第四步:排序。 当集合中存在多个 Advisor 时,Spring 会按照特定规则排序。排序的典型结果是:ExposeInvocationInterceptor → Before → AfterReturning → AfterThrowing → After → Around。这个顺序决定了拦截器链的执行次序。
关系三:拦截器链是最终执行形态
Advisor 收集完成并排序后,ProxyFactory 会将它们转换为 Interceptor 链。每个 Advisor 对应一个 Interceptor(如 MethodBeforeAdviceInterceptor、AroundAdviceInterceptor),链的顺序由 Advisor 的排序决定。
这个拦截器链存储在 AdvisedSupport 内部,它是管理拦截器链的核心类,内部通过 List 存储所有通知器。
当客户端调用代理对象的方法时,执行流程如下:
- 代理对象的 InvocationHandler(JDK 动态代理)或 MethodInterceptor(CGLIB 代理)捕获方法调用。
- 按排序顺序依次执行拦截器链中的每个 Interceptor。
- 每个拦截器根据其类型决定行为:前置通知直接执行后自动继续;环绕通知通过 proceed() 方法控制是否继续执行后续拦截器或目标方法;若不调用 proceed(),目标方法将不会执行。
- 当所有前置拦截器执行完毕,目标方法被调用。
- 目标方法返回后,后置通知执行;若抛出异常,异常通知执行;最终通知在任何情况下都会执行。
- 结果通过拦截器链逐层返回给客户端。
用一张文字版的流程图来呈现:
1客户端调用代理方法
2 ↓
3 拦截器链开始执行
4 ↓
5 ┌─→ ExposeInvocationInterceptor(传递上下文)
6 ├─→ Before Advice(前置逻辑)
7 ├─→ Around Advice → proceed() → 目标方法
8 ├─→ AfterReturning Advice(正常返回后)
9 ├─→ AfterThrowing Advice(异常时)
10 └─→ After Advice(最终清理)
11 ↓
12 结果返回客户端
13
三、深层理解:为什么需要 Advisor 这个中间层?
可能有人会问:为什么不直接让 Pointcut 和 Advice 配合,而非要引入 Advisor 这个中间层?
原因在于解耦与复用。
Advice 是逻辑的实现,它可以被多个不同的 Pointcut 复用。比如同一个日志记录 Advice,可以同时应用于服务层方法和控制器层方法,只需配置不同的 Pointcut 即可。而 Advisor 作为一个完整的配置单元,可以被注册为 Bean,被 Spring 自动识别和管理。
此外,Advisor 的引入让 Spring 的扩展变得极为灵活。开发者可以自定义 Advisor,实现针对特定注解、特定条件的方法拦截。例如,定义一个自定义注解 @Hero,然后创建对应的 MethodMatcher 和 Pointcut,再包装为 CustomAdvisor,即可实现对所有标注 @Hero 的方法的自动拦截。这种方式比直接操作 Pointcut 和 Advice 更加结构清晰、易于维护。
四、一张全景图:三者在 Spring AOP 体系中的位置
用层级关系来总结:
- 最顶层:Advisor(适配器),持有 Pointcut + Advice,是切面的完整描述。
- 中间层:Pointcut(切点)定义"在哪里",Advice(通知)定义"做什么"。
- 执行层:所有 Advice 最终被适配为 MethodInterceptor,组成拦截器链,在代理对象中按序执行。
- 支撑层:ProxyFactory 负责组装,AdvisedSupport 负责管理,AopProxy 负责生成代理对象(JDK 动态代理或 CGLIB 代理)。
Spring 最终关心的是 Advisor,因为它包含了完整信息。Pointcut 和 Advice 只是 Advisor 的两个组成部分,单独存在时无法完成切面织入。
五、结语
Spring AOP 的设计精妙之处,在于用最简洁的抽象覆盖了最复杂的场景。Pointcut 是眼睛,Advice 是双手,Advisor 是大脑——三者协作,让横切逻辑从业务代码中优雅地剥离出来,又在运行时精准地织回目标方法。
理解了这三者的关系模型,你就掌握了 Spring AOP 的骨架。无论是自定义切面、排查拦截器执行顺序,还是设计复杂的横切逻辑,这套模型都能为你提供清晰的思考框架。
记住那个公式:Advisor = Pointcut + Advice。这不仅是一个技术定义,更是 Spring AOP 设计哲学的浓缩——把"在哪做"和"做什么"封装在一起,才是一个完整的行动指令。