# 6.1. Spring中的切入点API

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

**6.1.1. 概念**

Spring 的切入点模型使切入点重用独立于通知类型。您可以使用相同的切入点定位不同的切面。

`org.springframework.aop.Pointcut`接口是中央接口，用于将切面定位到特定的类和方法。完整的接口如下：

```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 代理时执行此评估，以避免需要对每个方法调用进行测试。如果给定方法的两参数`matches`方法返回`true`，并且 MethodMatcher 的`isRuntime()`方法返回`true`，则在每次方法调用时都会调用三参数`matches`方法。这让切入点在目标通知开始之前立即查看传递给方法调用的参数。

大多数`MethodMatcher`实现都是静态的，这意味着它们的`isRuntime()`方法返回`false`. 在这种情况下，永远不会调用三参数的`matches`方法。

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

**6.1.2. 切入点操作**

Spring 支持切入点上的操作（特别是联合和交集）。

联合表示任一切入点匹配的方法。交集是指两个切入点匹配的方法。联合通常更有用。您可以使用类中的静态方法 `org.springframework.aop.support.Pointcuts`或使用同一包中的`ComposablePointcut`类来组合切入点。然而，使用 AspectJ 切入点表达式通常是一种更简单的方法。

**6.1.3. AspectJ 表达式切入点**

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

有关受支持的 AspectJ 切入点原语的讨论，请参见[前一章](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop)。

**6.1.4. 切入点的快捷实现**

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

**静态切入点**

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

本节的其余部分描述了 Spring 中包含的一些静态切入点实现。

**正则表达式切入点**

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

使用`JdkRegexpMethodPointcut`类，您可以提供模式字符串列表。如果其中任何一个匹配，则切入点计算为`true`。（因此，生成的切入点实际上是指定模式的并集。）

下面的例子展示了如何使用`JdkRegexpMethodPointcut`：

```xml
<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 封装了切入点和切面，如下例所示：

```xml
<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`。

**属性驱动切入点**

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

**动态切入点**

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

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

**控制流切入点**

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

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

**6.1.5. 切入点超类**

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

因为静态切入点是最有用的，所以你应该子类化 `StaticMethodMatcherPointcut`. 这只需要实现一个抽象方法（尽管您可以覆盖其他方法来自定义行为）。以下示例显示了如何子类化`StaticMethodMatcherPointcut`：

```java
class TestStaticPointcut extends StaticMethodMatcherPointcut {

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

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

**6.1.6. 自定义切入点**

因为 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://doc.shiker.tech/spring-he-xin-gong-neng/6.-spring-aop-api/6.1.-spring-zhong-de-qie-ru-dian-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.
