本节介绍 Spring 如何处理关键的切入点概念。

概念

Spring 的 pointcut 模型支持独立于建议类型的 pointcut 重用。您可以 使用相同的切入点针对不同的建议。

该接口是中央接口,用于 针对特定类别和方法提供有针对性的建议。完整的界面如下:org.springframework.aop.Pointcut

public interface Pointcut {

	ClassFilter getClassFilter();

	MethodMatcher getMethodMatcher();
}

将接口拆分为两部分允许重用类和方法 匹配零件和细粒度合成操作(例如执行“并集” 使用另一个方法匹配器)。Pointcut

该接口用于将切入点限制为一组给定的目标 类。如果该方法始终返回 true,则所有目标类都为 匹配。以下列表显示了接口定义:ClassFiltermatches()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);
}

该方法用于测试此点切口是否曾经 匹配目标类上的给定方法。当 AOP 时,可以执行此评估 创建代理是为了避免对每个方法调用进行测试的需要。如果 two-argument 方法返回给定方法,MethodMatcher 的方法返回,three-argument matches 方法为 在每次方法调用时调用。这样可以有针对性地查看传递的参数 在目标建议开始之前立即调用方法。matches(Method, Class)matchestrueisRuntime()true

大多数实现都是静态的,这意味着它们的方法 返回。在这种情况下,从不调用三参数方法。MethodMatcherisRuntime()falsematches

如果可能,请尝试将 pointcuts 设置为静态,允许 AOP 框架缓存 创建 AOP 代理时的切点评估结果。

点切口上的操作

Spring 支持对切点的操作(特别是并集和相交)。

并集表示任一点切口匹配的方法。 相交表示两个切点匹配的方法。 联合通常更有用。 可以使用类中的静态方法或使用同一包中的类来编写切点。但是,使用 AspectJ pointcut 表达式通常是一种更简单的方法。org.springframework.aop.support.PointcutsComposablePointcut

AspectJ 表达式切点

从 2.0 开始,Spring 使用的最重要的切入类型是 。这是一个切入点 使用 AspectJ 提供的库来分析 AspectJ 切入表达式字符串。org.springframework.aop.aspectj.AspectJExpressionPointcut

有关支持的 AspectJ 点切基元的讨论,请参阅上一章

便利点切入实现

Spring 提供了几个方便的切入点实现。您可以使用其中的一些 径直;其他的则用于在特定于应用程序的切入点中进行子类化。

静态切点

静态切点基于方法和目标类,不能考虑 该方法的参数。对于大多数用法来说,静态切点就足够了,而且是最好的。 Spring 只能在首次调用方法时计算一次静态切入点。 之后,无需在每次方法调用时再次评估切点。

本节的其余部分将介绍一些静态切入点实现,这些实现是 包含在 Spring 中。

正则表达式切入点

指定静态切点的一种明显方法是正则表达式。几个AOP 除了 Spring 之外,其他框架使这成为可能。 是通用的常规 在 JDK 中使用正则表达式支持的表达式切入。org.springframework.aop.support.JdkRegexpMethodPointcut

通过该类,您可以提供模式字符串列表。 如果其中任何一个是匹配项,则切入点的计算结果为 。(因此, 生成的切点实际上是指定模式的并集。JdkRegexpMethodPointcuttrue

以下示例演示如何使用:JdkRegexpMethodPointcut

<bean id="settersAndAbsquatulatePointcut"
		class="org.springframework.aop.support.JdkRegexpMethodPointcut">
	<property name="patterns">
		<list>
			<value>.*set.*</value>
			<value>.*absquatulate</value>
		</list>
	</property>
</bean>

Spring 提供了一个名为 的便利类,它让我们 还要引用 an(请记住,在建议之前,an 可以是拦截器, 抛出建议等)。在幕后,Spring 使用了 . 使用简化了接线,因为一个 bean 封装了两者 pointcut 和 advice,如以下示例所示:RegexpMethodPointcutAdvisorAdviceAdviceJdkRegexpMethodPointcutRegexpMethodPointcutAdvisor

<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>

您可以与任何类型一起使用。RegexpMethodPointcutAdvisorAdvice

属性驱动的 Pointcuts

静态切入的一种重要类型是元数据驱动的切入。这使用 元数据属性(通常为源级元数据)的值。

动态切点

动态切点比静态切点的评估成本更高。他们考虑到 方法参数以及静态信息。这意味着他们必须 在每次方法调用时进行评估,并且结果不能缓存,因为参数会 不同。

主要的例子是切入点。control flow

控制流点切口

弹簧控制流切点在概念上类似于 AspectJ 切点, 虽然功能较弱。(目前无法指定切入点运行 低于与另一个切口匹配的连接点。控制流切点与 当前调用堆栈。例如,如果联接点是由方法调用的,则它可能会触发 在包中或按类。控制流量切点 通过使用类指定。cflowcom.mycompany.webSomeCallerorg.springframework.aop.support.ControlFlowPointcut

在运行时评估控制流切点的成本要比甚至高得多 其他动态切点。在 Java 1.4 中,成本大约是其他动态的 5 倍 切入点。

Pointcut 超类

Spring 提供了有用的 pointcut 超类来帮助你实现自己的 pointcut。

由于静态切点最有用,因此您可能应该对 进行子类化。这只需要实现一个 abstract 方法(尽管您可以重写其他方法来自定义行为)。这 以下示例显示了如何子类化:StaticMethodMatcherPointcutStaticMethodMatcherPointcut

  • 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
	}
}

还有用于动态切点的超类。 您可以将自定义切入点与任何建议类型一起使用。

自定义点切口

因为 Spring AOP 中的切点是 Java 类而不是语言特性(如 AspectJ),您可以声明自定义切口,无论是静态的还是动态的。习惯 Spring 中的切点可以任意复杂。但是,我们建议使用 AspectJ 点切口 表达语言,如果可以的话。

更高版本的 Spring 可能会提供对 JAC 提供的“语义切入”的支持,例如,“所有更改目标对象中实例变量的方法”。