Pointcut API in Spring
本部分介绍了 Spring 如何处理关键切入点概念。
Concepts
Spring 的切入点模型支持与建议类型无关的切入点重用。你可以使用相同的切入点针对不同的建议。
org.springframework.aop.Pointcut
接口是中心接口,用于为特定类和方法提供指导。完整的界面如下:
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
将 Pointcut
接口分为两部分,可以实现类和方法匹配部分的重用,以及精细组合运算(例如与其他方法匹配器执行“并集”)。
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 代理时缓存切入点评估结果。 |
Operations on Pointcuts
Spring 支持切点上的运算(特别是并集和交集)。
并集是指两个切点都匹配的方法。交集是指两个切点都匹配的方法。并集通常更有用。可以通过使用 org.springframework.aop.support.Pointcuts
类中的静态方法或使用同一个包中的 ComposablePointcut
类来组合切点。但是,使用 AspectJ 切点表达式通常是一种更简单的方法。
AspectJ Expression Pointcuts
自 2.0 以来,Spring 使用的最重要的切点类型是 org.springframework.aop.aspectj.AspectJExpressionPointcut
。这是使用 AspectJ 提供的库来解析 AspectJ 切点表达式字符串的切点。
请参阅 previous chapter 以了解受支持的 AspectJ 切入点基元讨论。
Convenience Pointcut Implementations
Spring 提供了几个方便的切点实现。你可以直接使用其中的某些切点;其他一些切点则旨在应用程序特定的切点中进行子类化。
Static Pointcuts
静态切点基于方法和目标类,且无法考虑方法的参数。对于大多数用法,静态切点就足够了——而且是最好的。当首先调用一个方法时,Spring 只能评估一次静态切点。在那之后,无需通过每次方法调用重新评估切点。
本节的其余部分将描述一些包含在 Spring 中的静态切点实现。
Regular Expression Pointcuts
指定静态切点的一个明显方法是正则表达式。除了 Spring 之外,还有好几个 AOP 框架支持这种方法。org.springframework.aop.support.JdkRegexpMethodPointcut
是一个通用的正则表达式切点,它使用 JDK 中的正则表达式支持。
使用 JdkRegexpMethodPointcut
类,你可以提供一个模式字符串列表。如果其中任何一个是匹配项,切点将评估为 true
。(结果,所得到的切点实际上是指定模式的并集。)
以下示例演示了如何使用 JdkRegexpMethodPointcut
:
-
Java
-
Kotlin
-
Xml
@Configuration
public class JdkRegexpConfiguration {
@Bean
public JdkRegexpMethodPointcut settersAndAbsquatulatePointcut() {
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPatterns(".*set.*", ".*absquatulate");
return pointcut;
}
}
@Configuration
class JdkRegexpConfiguration {
@Bean
fun settersAndAbsquatulatePointcut() = JdkRegexpMethodPointcut().apply {
setPatterns(".*set.*", ".*absquatulate")
}
}
<bean id="settersAndAbsquatulatePointcut"
class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
Spring 提供了一个名为 RegexpMethodPointcutAdvisor
的便捷类,使我们也可以引用一个 Advice
(请记住,Advice
可以是一个拦截器、前通知、抛出通知和其他的)。在后台,Spring 使用 JdkRegexpMethodPointcut
。使用 RegexpMethodPointcutAdvisor
简化了连接,因为一个 bean 封装了切点和通知,如下例所示:
-
Java
-
Kotlin
-
Xml
@Configuration
public class RegexpConfiguration {
@Bean
public RegexpMethodPointcutAdvisor settersAndAbsquatulateAdvisor(Advice beanNameOfAopAllianceInterceptor) {
RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor();
advisor.setAdvice(beanNameOfAopAllianceInterceptor);
advisor.setPatterns(".*set.*", ".*absquatulate");
return advisor;
}
}
@Configuration
class RegexpConfiguration {
@Bean
fun settersAndAbsquatulateAdvisor(beanNameOfAopAllianceInterceptor: Advice) = RegexpMethodPointcutAdvisor().apply {
advice = beanNameOfAopAllianceInterceptor
setPatterns(".*set.*", ".*absquatulate")
}
}
<bean id="settersAndAbsquatulateAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="beanNameOfAopAllianceInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
你可以将 RegexpMethodPointcutAdvisor
与任何类型的 Advice
结合使用。
Pointcut Superclasses
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
}
}
还有一些动态切入点超类。你可以将自定义切入点与任何类型的建议结合使用。