Skip to content

Spring 中的 Advisor API

在 Spring 中,Advisor 是一个切面(Aspect),它仅包含一个与切入点(Pointcut)表达式关联的单一通知(Advice)对象。

除了“引入(Introductions)”这一特殊情况外,任何 Advisor 都可以与任何通知一起使用。org.springframework.aop.support.DefaultPointcutAdvisor 是最常用的 Advisor 类。它可以与 MethodInterceptorMethodBeforeAdviceThrowsAdvice 一起使用。

在同一个 AOP 代理中,Spring 允许混合使用不同的 Advisor 和通知类型。例如,你可以在一个代理配置中同时使用环绕拦截通知、异常通知和前置通知。Spring 会自动创建必要的拦截器链。


补充教学

1. Advisor 的角色:Pointcut 与 Advice 的“纽带”

在 Spring AOP 的底层设计中,Advisor 是拦截逻辑的最小完整单元

  • Pointcut 决定了“在哪里拦”。
  • Advice 决定了“拦住后做什么”。
  • Advisor 则是将这两者打包成一个 Bean。

当你使用 @Aspect 注解时,Spring 内部其实会将每一个 @Before@Around 方法解析为一个一个的 InstantiationModelAwarePointcutAdvisorImpl 实例。

2. DefaultPointcutAdvisor 实战代码

虽然现代开发中很少手写它,但在工具类或中间件中,它是编程式织入的基础。

java
// 1. 定义通知
MethodBeforeAdvice advice = (m, args, target) -> System.out.println("执行方法: " + m.getName());

// 2. 定义切入点 (匹配所有以 service 结尾的方法)
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedName("*service");

// 3. 将两者组合进 Advisor
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
kotlin
// 1. 定义通知
val advice = MethodBeforeAdvice { m, _, _ -> println("执行方法: ${m.name}") }

// 2. 定义切入点
val pointcut = NameMatchMethodPointcut().apply {
    setMappedName("*service")
}

// 3. 将两者组合进 Advisor
val advisor = DefaultPointcutAdvisor(pointcut, advice)

3. Advisor 的排序:决定执行顺序

当一个方法被多个 Advisor 拦截时,执行顺序至关重要。

  • 实现 Ordered 接口:你可以让你的自定义 Advisor 实现 org.springframework.core.Ordered 接口,或者使用 @Order 注解。
  • 数值越小越优先:Order 值越小的 Advisor,其通知在“进入”方法时越先执行,而在“退出”方法时(对于环绕/后置通知)越晚结束。
  • 默认配置:在 XML 或配置类中定义的顺序通常就是它们的执行顺序。

4. Advisor vs. Aspect 的区别

  • Advisor:Spring AOP 特有的概念。一个 Advisor 只能包含一个通知。它是原子性的。
  • Aspect:通用的 AOP 概念。一个切面(类)可以包含多个通知(方法)。
  • 关系:在 Spring 中,一个 @Aspect 标注的类通常会被“拆解”成一组 Advisor 列表存入拦截器链。

Based on Spring Framework.