Spring 中的切入点 API
本节介绍 Spring 如何处理关键的切入点概念。
概念
Spring 的切入点模型支持独立于通知类型重用切入点。你可以使用相同的切入点来定位不同的通知。
org.springframework.aop.Pointcut
接口是核心接口,用于将通知定位到特定的类和方法。完整的接口如下:
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
将 Pointcut
接口拆分为两部分,可以重用类和方法匹配部分,并进行细粒度的组合操作(例如,与另一个方法匹配器执行“union
”)。
ClassFilter
接口用于将切入点限制到给定的目标类集合。如果 matches()
方法始终返回 true,则匹配所有目标类。以下列表显示了 ClassFilter
接口定义:
public interface ClassFilter {
boolean matches(Class clazz);
}
MethodMatcher
接口通常更重要。完整的接口如下:
public interface MethodMatcher {
boolean matches(Method m, Class<?> targetClass);
boolean isRuntime();
boolean matches(Method m, Class<?> targetClass, Object... args);
}
matches(Method, Class)
方法用于测试此切入点是否曾匹配目标类上的给定方法。此评估可以在创建 AOP 代理时执行,以避免在每次方法调用时进行测试。如果两参数的 matches
方法对于给定方法返回 true
,并且 MethodMatcher
的 isRuntime()
方法返回 true
,则在每次方法调用时都会调用三参数的 matches
方法。这允许切入点在目标通知开始之前立即查看传递给方法调用的参数。
大多数 MethodMatcher
实现是静态的,这意味着它们的 isRuntime()
方法返回 false
。在这种情况下,三参数的 matches
方法永远不会被调用。
如果可能,请尝试使切入点静态化,允许 AOP 框架在创建 AOP 代理时缓存切入点评估结果。 |
切入点上的操作
Spring 支持对切入点进行操作(特别是联合和交集)。
联合意味着任一切入点匹配的方法。
交集意味着两个切入点都匹配的方法。
联合通常更有用。
你可以通过使用 org.springframework.aop.support.Pointcuts
类中的静态方法或使用同一包中的 ComposablePointcut
类来组合切入点。然而,使用 AspectJ 切入点表达式通常是一种更简单的方法。
AspectJ 表达式切入点
自 2.0 版本以来,Spring 使用的最重要的切入点类型是 org.springframework.aop.aspectj.AspectJExpressionPointcut
。这是一个使用 AspectJ 提供的库来解析 AspectJ 切入点表达式字符串的切入点。
有关支持的 AspectJ 切入点原语的讨论,请参阅 上一章。
方便的切入点实现
Spring 提供了几个方便的切入点实现。你可以直接使用其中一些;其他一些则旨在在特定于应用程序的切入点中进行子类化。
静态切入点
静态切入点基于方法和目标类,不能考虑方法的参数。静态切入点足以满足大多数用途,并且是最好的选择。Spring 只能在方法首次调用时评估一次静态切入点。之后,无需在每次方法调用时再次评估切入点。
本节的其余部分描述了 Spring 中包含的一些静态切入点实现。
正则表达式切入点
指定静态切入点的一种显而易见的方法是正则表达式。除了 Spring 之外,还有几个 AOP 框架也提供了这种功能。org.springframework.aop.support.JdkRegexpMethodPointcut
是一个通用的正则表达式切入点,它使用 JDK 中的正则表达式支持。
使用 JdkRegexpMethodPointcut
类,你可以提供一个模式字符串列表。如果其中任何一个匹配,则切入点评估为 true
。(因此,结果切入点实际上是指定模式的联合。)
以下示例展示了如何使用 JdkRegexpMethodPointcut
:
Spring 提供了一个名为 RegexpMethodPointcutAdvisor
的便利类,它允许我们同时引用一个 Advice
(请记住,Advice
可以是拦截器、前置通知、抛出通知等)。在幕后,Spring 使用 JdkRegexpMethodPointcut
。使用 RegexpMethodPointcutAdvisor
简化了连接,因为一个 bean 封装了切入点和通知,如以下示例所示:
你可以将 RegexpMethodPointcutAdvisor
与任何 Advice
类型一起使用。
切入点超类
Spring 提供了有用的切入点超类,以帮助你实现自己的切入点。
因为静态切入点最有用,所以你可能应该子类化 StaticMethodMatcherPointcut
。这只需要实现一个抽象方法(尽管你可以覆盖其他方法来自定义行为)。以下示例展示了如何子类化 StaticMethodMatcherPointcut
:
-
Java
-
Kotlin
class TestStaticPointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method m, Class targetClass) {
// return true if custom criteria match
}
}
class TestStaticPointcut : StaticMethodMatcherPointcut() {
override fun matches(method: Method, targetClass: Class<*>): Boolean {
// return true if custom criteria match
}
}
也有用于动态切入点的超类。 你可以将自定义切入点与任何通知类型一起使用。