Spring 中的 Advisor API
在 Spring 中,Advisor 是一个切面(Aspect),它仅包含一个与切入点(Pointcut)表达式关联的单一通知(Advice)对象。
除了“引入(Introductions)”这一特殊情况外,任何 Advisor 都可以与任何通知一起使用。org.springframework.aop.support.DefaultPointcutAdvisor 是最常用的 Advisor 类。它可以与 MethodInterceptor、MethodBeforeAdvice 或 ThrowsAdvice 一起使用。
在同一个 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列表存入拦截器链。