SpringAOP之切入点PointcutAPI详细介绍及使用
环境:Spring5.3.23概述
在工作中用的最多的就是通过@Aspect 实现AOP功能;要在Spring配置中使用@Aspect 切面,需要启用Spring支持,以便基于@Aspect 切面配置Spring AOP,并根据条件自动代理bean。通过自动代理,如果Spring确定某个bean符合一个或多个切面的建议,它会自动为该bean生成一个代理来拦截方法调用,并确保按需运行通知。
可以通过XML或java风格的配置启用@AspectJ支持。在这两种情况下,还需要确保AspectJ的aspectjweaver.jar库位于应用程序的类路径上(版本1.8或更高)。
通过注解方式开启@Aspect支持@Configuration @EnableAspectJAutoProxy public class AppConfig { }
通过XML开启@Aspect支持
定义AspectJ切面package com.pack.aspect; import org.aspectj.lang.annotation.Aspect; @Aspect public class CustomAspect { // 定义切入点 @Pointcut("execution(* com.pack.service..*.(..))") private void log() {} // 定义通知 @Before("log()") // @Before("execution(* com.pack.service..*.(..))") 也可以直接这样写 public void recordLogBefore() { // ... } @AfterReturning("log()") public void recordLogAfter(){ // ... } }
上面简单回顾了在工作中使用@Aspect定义切面实现AOP功能Spring AOP APISpring中的切入点API
Spring的切入点模型支持独立于通知类型的切入点重用。可以使用相同的切入点定位不同的通知。
pointcut接口是中心接口,用于为特定类和方法提供建议。完整的接口如下:public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); }
将切入点接口拆分为两个部分允许重用类和方法匹配部分以及细粒度的组合操作。
ClassFilter 接口用于将切入点限制为给定的目标类集。如果matches()方法总是返回true,则匹配所有目标类。ClassFilter 接口的定义如下列代码清单所示:public interface ClassFilter { boolean matches(Class clazz); }
该类专门用来匹配每一个Bean是否符合条件,只有匹配了才可为其创建代理。
MethodMatcher 接口通常更重要。完整的接口如下:public interface MethodMatcher { /** * 在运行目标类的方法时判断当前的执行的方法是否匹配,如果匹配才会执行 * 相关的通知 */ boolean matches(Method m, Class<?> targetClass); /** * 上面2个参数的matches返回true才会执行isRuntime * 该方法的返回值决定了下面3个参数的matches方法是否会被执行 * 如果返回true,才会进行下面3个参数的执行。返回false将不会执行下面方法 */ boolean isRuntime(); /** * 该方法是否会被执行是由上面的isRuntime方法决定,只有返回true才会执行 * 如果isRuntime方法返回true,那么会将每一个Advisor中定义的通知 * (这些通知会被转换为MethodInterceptor)包装为InterceptorAndDynamicMethodMatcher * 最后在通过ReflectiveMethodInvocation执行时会判断当前对象如果为ReflectiveMethodInvocation * 则进行MethodMatcher3个参数的matches调用,这里就可以对参数进行相应的校验判断, * 是否进行通知的继续调用,如果匹配则调用当前的MethodInterceptor,否则直接调用下一个 */ boolean matches(Method m, Class<?> targetClass, Object... args); }对切入点的操作
Spring支持切入点上的操作(特别是union和intersection)。Union表示任意一个切入点匹配的方法。交集意味着两个切入点匹配的方法。Union通常更有用。可以使用org.springframework.aop.support.Pointcuts 类中的静态方法来组合切入点,也可以使用同一个包中的 ComposablePointcut 类。然而,使用AspectJ切入点表达式通常是一种更简单的方法。
Union表示了多个Pointcut都需要匹配才算匹配public abstract class Pointcuts { public static Pointcut union(Pointcut pc1, Pointcut pc2) { return new ComposablePointcut(pc1).union(pc2); } }
ComposablePointcut public class ComposablePointcut implements Pointcut, Serializable { private ClassFilter classFilter; private MethodMatcher methodMatcher; public ComposablePointcut(Pointcut pointcut) { this.classFilter = pointcut.getClassFilter(); this.methodMatcher = pointcut.getMethodMatcher(); } public ComposablePointcut union(Pointcut other) { this.methodMatcher = MethodMatchers.union(this.methodMatcher, this.classFilter, other.getMethodMatcher(), other.getClassFilter()); this.classFilter = ClassFilters.union(this.classFilter, other.getClassFilter()); return this; } }
MethodMatchers.union static MethodMatcher union(MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) { return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ? new ClassFilterAwareUnionIntroductionAwareMethodMatcher(mm1, cf1, mm2, cf2) : new ClassFilterAwareUnionMethodMatcher(mm1, cf1, mm2, cf2)); }
如上假设返回ClassFilterAwareUnionMethodMatcher private static class ClassFilterAwareUnionMethodMatcher extends UnionMethodMatcher { private final ClassFilter cf1; private final ClassFilter cf2; public ClassFilterAwareUnionMethodMatcher(MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) { super(mm1, mm2); this.cf1 = cf1; this.cf2 = cf2; } } private static class UnionMethodMatcher implements MethodMatcher, Serializable { // 最终的核心就是分别判断两个Pointcut对应的ClassFilter,MethodMatcher // 只要其中一个返回true即可 public boolean matches(Method method, Class<?> targetClass) { return (matchesClass1(targetClass) && this.mm1.matches(method, targetClass)) || (matchesClass2(targetClass) && this.mm2.matches(method, targetClass)); } }方便的切入点实现
Spring为我们提供了几个便捷的切入点实现类可以直接使用。
静态切入点,静态切入点基于方法和目标类,不能考虑方法的参数。对于大多数用法,静态切入点就足够了,而且是最好的。Spring只能在方法第一次被调用时对静态切入点进行一次评估。之后,就不需要对每个方法调用再次评估切入点了。
正则表达式切点
指定静态切入点的一个明显方法是正则表达式。除了Spring之外,还有几个AOP框架使之成为可能。org.springframework.aop.support.JdkRegexpMethodPointcut 是一个通用正则表达式切入点,它使用JDK中的正则表达式支持。
使用JdkRegexpMethodPointcut 类,可以提供一组模式字符串。如果其中任何一个匹配,切入点计算为true。 .*set.* .*save
[ ]
动态切入点
动态切入点的评估成本比静态切入点高。它们既考虑了方法参数,也考虑了静态信息。这意味着每次方法调用都必须计算它们,而且结果不能缓存,因为参数不同。
核心切入点类: ControlFlowPointcut public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable { private final Class<?> clazz; private final String methodName; /** * 构造一个新的切入点,它匹配给定类中给定方法下面的所有调用。 * 如果没有给出方法名,则匹配给定类下的所有控制流。 */ public ControlFlowPointcut(Class<?> clazz, @Nullable String methodName) { this.clazz = clazz; this.methodName = methodName; } public boolean matches(Method method, Class<?> targetClass) { return true; } @Override public boolean isRuntime() { return true; } @Override public boolean matches(Method method, Class<?> targetClass, Object... args) { // 遍历当前的执行栈中的所有方法是否有匹配当前在构造方法中传入的方法名,有则进行相应的通知调用 // 简单点说就是:拦截任何被创建代理类的方法,如果这些方法在执行过程中有调用构造参数中传入的Class 和Method那么就是匹配的 for (StackTraceElement element : new Throwable().getStackTrace()) { if (element.getClassName().equals(this.clazz.getName()) && (this.methodName == null || element.getMethodName().equals(this.methodName))) { return true; } } return false; } }
Pointcut超类
Spring提供了有用的切入点超类来帮助您实现自己的切入点。
因为静态切入点最有用,你可能应该子类化StaticMethodMatcherPointcut 。这只需要实现一个抽象方法(尽管你可以覆盖其他方法来定制行为)。下面的例子展示了如何子类化StaticMethodMatcherPointcut :public class CustomStaticPointcut extends StaticMethodMatcherPointcut { public boolean matches(Method m, Class targetClass) { // return true if custom criteria match } }
完毕!!!
下一节介绍《Spring AOP之通知Advice API详细介绍及使用》
关注 我长期更新
SpringBoot AOP 9种切入点详细使用说明
Spring 自定义Advisor以编程的方式实现AOP
Spring AOP切入点类型及系统提供的非常常用的切入点
Spring AOP实现原理源码详细分析
Spring AOP动态代理失效的解决方法@Transactional为何会失效
木白之家苹果手机更换电池教程(五)苹果手机从11系列开始,就可以显示电池健康度了,也是大家熟知的降频门事件,苹果认为,电池健康度低于80以后,手机存在自动关机和软件自动退出的意外风险,所以当电池健康度低于80以后,
孕早期孕妈的甲状腺功能状态,直接影响宝宝的生长发育孕早期的检查除了超声,还有一个比较重要的检查,就是甲状腺功能。在孕10周前,宝宝所需甲状腺激素全部由孕妈妈提供,所以孕妈妈的甲状腺功能状态,直接影响宝宝的神经系统分化和发育。到了孕
推荐6本好书,祝女孩们成长为更好的自己新的一年里,祝愿所有的姐妹们都能成为更好的自己,今天给姐妹们推荐6本成长类好书。这些书的作者都是女性,写得自己一路摸爬滚打的故事和经验,启迪女孩们心智让大家找到天赋优势,并成长为更
楼上邻居女儿天天弹钢琴影响了楼下大妈,楼下大妈用震楼器报复浙江,杭州。楼上封女士为了培养孩子兴趣,不分昼夜教孩子练习钢琴,严重影响了邻居们的正常生活,楼下邻居多次上门协商无果后,一气之下安装了镇楼器进行报复,邻居我奉陪到底!封女士辞去工作
各位家长,警惕儿童玩火!又有熊孩子把家烧了!来源中国消防有些孩子调皮贪玩让大家十分无奈但有时候熊孩子玩过头真的能让人欲哭无泪近日,江西宜春一村民房屋起火接到报警后消防救援人员立即前往处置消防员到达现场后发现起火建筑为四层民房
今日关注主持人黎绮雯家庭和事业两不误,气质甚至更胜从前广东电视珠江台今日关注节目开播于2005年3月21日,随着2022年走进历史,它也迎来了播出的第十八个年头,曾几何时,该节目带给广东观众的回忆实在太多了,只可惜的是,再好的节目也会
蔡明,一切都该结束了文文亦范编辑小丁有人曾说很多人都在吐槽春晚难看,甚至要求取消,其实这是完全没有必要的,这年头要找一个全国性的项目,还可以随意批评,既不屏蔽又不请喝咖啡真的很难。兔年离我们越来越近,
2011年央视春晚赵本山面对王小丽卡壳,及时救场,时间刚好弥补要说春晚,还是得以前的。以前的春晚要多野有多野,主要是没有太多的条条框框。春晚中让我们印象最深刻的还是赵本山的小品,那叫一个接地气。赵本山大叔曾先后上过21次春晚,其中有15次被总
春晚没有董卿的舞台大家还是没有习惯董卿的离开能让更多人明白,其实人生的旅途无论走得多远,终要回归到家的那一方温暖空间。从2005年至2017年,董卿在春晚的舞台上走了13年,春晚没有董卿的第二年,话
周周有戏睇俄罗斯音乐剧安娜卡列尼娜中文版周周有戏睇,湾区粤韵由你启!今周有咩好戏?开心麻花爆笑音乐剧求婚女王爱乐之城经典电影音乐作品音乐会俄罗斯音乐剧安娜卡列尼娜中文版广州开心麻花爆笑音乐剧求婚女王地点广州正佳大剧院开心
2023年央视春晚李思思还能当主持人吗?与马凡舒相比又怎么样呢?近日,李思思称自己得了斩腰症,白天还好可以方便起坐,一到晚上就疼地厉害,腰部就好像是被折断了一样。图中我们可以看到李思思虽然生病,嘴唇也没什么血色,但是面容气色还是不错的。作为董卿