Spring AOP 之 Pointcut API

官方地址:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-api

Pointcut的API

Spring的切入点模型使切入点重用独立于通知类型,可以用同一个切入点针对不同的Advice。

org.springframework.aop.Pointcut接口是中心接口,用于针对特定类和方法的建议

public interface Pointcut {

    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();
}

切入点接口拆分为两部分,

  • 允许重用类
  • 方法匹配部分以及细粒度的组合操作(例如与另一个方法匹配器执行“联合”)

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。在这种情况下,不会调用三参数匹配方法。

尽可能使切入点成为静态的,允许AOP框架在创建AOP代理时缓存切入点计算的结果。

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

  • Union并集是指方法匹配上的所有pointcut
  • Insertion交集是指方法共同匹配的pointcut

Union更常用

可以使用org.springframework.aop.support.Pointcuts类中的静态方法或者使用同一个包中底下的ComposablePointcut类。

不过,使用AspectJ切入点表达式通常是一种更简单的方法。

  •  2.0之后,Spring使用的最重要的切入点类型是org.springframework.aop.aspectj.AspectJExpressionPointcut.
  • 这是一个切入点,它使用AspectJ提供的库来解析AspectJ切入点表达式字符串.

Static Pointcuts

静态切入点基于方法和目标类,不能应用到方法参数。

当方法第一次被调用时,Spring只能对静态切入点计算一次。之后每次方法调用不需要再次计算切入点。

Regular Expression Pointcuts

指定一个静态切入点的一个明显方法是正则表达式。

除了Spring之外很少有AOP框架实现这个功能

org.springframework.aop.support.JdkRegexpMethodPointcut方法是一个通用正则表达式切入点,使用了JDK中的正则表达式支持。

使用JdkRegexpMethodPointcut类,可以提供模式字符串的列表。

如果其中任何一个匹配,则切入点的计算结果为true。(因此,生成的切入点实际上是指定模式的并集。)

使用JdkRegexpMethodPointcut

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

Pointcut中的execution匹配参数

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?) 

括号中各个pattern分别表示:

  • 修饰符匹配(modifier-pattern?)
  • 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
  • 类路径匹配(declaring-type-pattern?)
  • 方法名匹配(name-pattern)可以指定方法名 或者 *代表所有, set* 代表以set开头的所有方法
  • 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“*”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数
  • 异常类型匹配(throws-pattern?)
  • 其中后面跟着“?”的是可选项
1)execution(* *(..))  
//表示匹配所有方法  
2)execution(public * com. savage.service.UserService.*(..))  
//表示匹配com.savage.server.UserService中所有的公有方法  
3)execution(* com.savage.server..*.*(..))  
//表示匹配com.savage.server包及其子包下的所有方法

Spring提供了一个名为RegexpMethodPointcutAdvisor的便利类,它还允许我们引用一个通知

一个通知可以是一个拦截器,在通知之前,抛出通知等等),在背后,Spring使用JdkRegexpMethodPointcut。

RegexpMethodPointcutAdvisor简化了连接,一个bean同时封装了切入点和通知

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

Attribute-driven Pointcuts

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

Dynamic pointcuts

动态切入点比静态切入点消耗资源多。它们考虑了方法参数和静态信息。这意味着必须在每次方法调用时对它们进行求值,并且不能缓存结果,因为参数会有所不同。

Control Flow Pointcuts

Spring控制流切入点在概念上类似于aspectjcflow切入点,但功能较弱。当前无法指定一个切入点在另一个切入点匹配的连接点下运行。

控制流切入点与当前调用堆栈匹配。

例如,如果连接点是由com.mycompany.web包或SomeCaller类。通过使用org.springframework.aop.support.ControlFlowPointcut指定控制流切入点

  • 控制流切入点在运行时的计算成本甚至比其他动态切入点都要高。在Java1.4中,成本大约是其他动态切入点的五倍。

Pointcut Superclasses

Spring提供了有用的切入点父类来实现自己的切入点。

因为静态切入点最有用,所以您可能应该将StaticMethodMatcherPointcut子类化。

这只需要实现一个抽象方法(尽管您可以重写其他方法来定制行为):

class TestStaticPointcut extends StaticMethodMatcherPointcut {

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

Custom Pointcuts

  • 因为SpringAOP中的切入点是Java类而不是语言特性(如AspectJ),所以可以声明自定义切入点,无论是静态的还是动态的。
  • Spring中的自定义切入点可以是任意复杂的。但是,如果可以,我们建议使用AspectJ切入点表达式语言。
  • Spring的更高版本可能支持JAC提供的“语义切入点”,例如“所有改变目标对象中实例变量的方法”
posted @ 2021-04-20 13:15  YC-L  阅读(18)  评论(0编辑  收藏  举报