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。在这种情况下,不会调用三参数匹配方法。
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提供的“语义切入点”,例如“所有改变目标对象中实例变量的方法”
睁开眼,书在面前 闭上眼,书在心里