# 6.1Pointcut API

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

## 6.1.1 概念

Spring的切入点模型支持独立于通知类型的切入点重用。你可以使用相同的切入点来通知不同的建议目标。

org.springframework.aop.Pointcut接口是一个中心接口，用于将通知定向到特定的类和方法。完整interface如下：

```java
public interface Pointcut {

    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();

}
```

将Pointcut接口拆分为两部分允许重用类和方法匹配部分以及细粒度组合操作（例如，使用另一个方法匹配器执行“联合”）。

ClassFilter接口用于将切入点限制为一组给定的目标类。如果matches（）方法始终返回true，则所有目标类都匹配。下面的列表显示ClassFilter接口定义：

```java
public interface ClassFilter {

    boolean matches(Class clazz);
}
```

MethodMatcher接口通常来说更加重要。完整的接口如下：

```java
public interface MethodMatcher {

    boolean matches(Method m, Class targetClass);

    boolean isRuntime();

    boolean matches(Method m, Class targetClass, Object[] args);
}
```

matches（method，class）方法用于测试此切入点是否与目标类上的给定方法匹配。当创建AOP代理时可以执行此评估，以避免对每个方法调用进行测试。如果两个参数匹配的方法对于给定的方法返回true，而methodMatcher的isRuntime（）方法返回true，则在每次方法调用时都会调用三个参数匹配的方法。这允许切入点查看在执行目标通知之前立即传递给方法调用的参数。

大多数MethodMatcher实现是静态的，这意味着它们的isRuntime（）方法返回false。在本例中，从不调用三个参数matches方法。

> 如果可能，尝试使切入点静态化，允许AOP框架在创建AOP代理时缓存切入点评估的结果。

## 6.1.2 Pointcuts的操作

Spring支持对切入点的操作（尤其是Union和intersection）。

Union是指切入点匹配任意一个方法。intersection表示切入点同时匹配的方法。Union通常更有用。你可以使用org.springframework.aop.support.Pointcuts类中的静态方法或在同一个包中使用ComposablePointcut类来撰写切入点。然而，使用AspectJ切入点表达式通常是一种更简单的方法。

## 6.1.3 AspectJ表达式Pointcuts

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

有关支持的aspectj切入点原语的讨论，请参阅上一章。

## 6.1.4 方便的Pointcut实现

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

**静态切入点**

静态切入点基于方法和目标类，不能考虑方法的参数。静态切入点对于大多数使用来说是最好的。当第一次调用方法时，Spring只能计算一次静态切入点。之后，不需要对每个方法调用再次计算切入点。 本节的其余部分描述了Spring中包含的一些静态切入点实现。

*正则表达式切入点*

指定静态切入点的一个明显方法是正则表达式。除了Spring，还有几个AOP框架使这成为可能。org.springframework.aop.support.JdkRegexpMethodPointcut是一个通用的正则表达式切入点，它使用JDK中的正则表达式支持。

通过JdkRegexpMethodPointcut类，可以提供模式字符串的列表。如果其中任何一个匹配，则切入点的计算结果为true。（因此，结果实际上是这些切点的并集。）

下面的示例演示如何使用JdkRegexpMethodPointcut：

```markup
<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同时封装了pointcut和advice，如下示例所示：

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

你可以在任何Advice类型中使用RegexpMethodPointcutAdvisor。

*属性驱动Pointcuts*

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

**动态pointcuts**

动态切入点的计算成本比静态切入点高。它们考虑了方法参数和静态信息。这意味着必须用每个方法调用对它们进行评估，并且不能缓存结果，因为参数会有所不同。

主要的例子是控制流切入点。

*控制流切入点*

Spring控制流切入点在概念上与AspectJ CFlow切入点相似，但功能较弱。（目前无法指定在与另一个切入点匹配的连接点下方执行切入点。）控制流切入点与当前调用堆栈匹配。例如，如果连接点是由com.mycompany.web包中的方法或SomeCaller类调用的，则它可能会激发。通常使用org.springframework.aop.support.ControlFlowPointcut类指定控制流切入点。

> 控制流切入点在运行时的计算成本比其他动态切入点都要高。在Java 1.4中，成本是其他动态切入点的五倍。

## 6.1.5 Pointcut 父类

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

因为静态切入点最有用，所以你可能应该将StaticMethodMatcherPointCut子类化。这只需要实现一个抽象方法（尽管你可以重写其他方法来定制行为）。下面的示例显示如何将StaticMethodMatcherPointCut子类化：

```java
class TestStaticPointcut extends StaticMethodMatcherPointcut {

    public boolean matches(Method m, Class targetClass) {
        // return true if custom criteria match
    }
}
```

还有动态切入点的超类。你可以对任何通知类型使用自定义切入点。

## 6.1.6 自定义Pointcuts

因为Spring AOP中的切入点是Java类，而不是语言特征（如AspectJ中），所以可以声明自定义切入点，无论是静态的还是动态的。Spring中的自定义切入点可以任意复杂。但是，如果可以的话，我们建议使用AspectJ切入点表达式语言。

> Spring的较新版本可能支持jac-提供的“语义切入点”，例如，“所有更改目标对象中实例变量的方法”。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flydean.com/spring-framework-documentation5/core-technologies/6.spring-aop-apis/6.1pointcut-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
