【源码】Spring AOP 4 Pointcut
【源码】Spring AOP 4 Pointcut
- 前言
- Pointcut
- ClassFilter
- AnnotationClassFilter
- AnnotationCandidateClassFilter
- MethodMatcher
- StaticMethodMatcher
- AnnotationMethodMatcher
- StaticMethodMatcherPointcut
- NameMatchMethodPointcut
- demo
- StaticMethodMatcherPointcutDemo
- ComposablePointcut
- demo
- AspectJExpressionPointcut
- 类图
- Pointcut
- ClassFilter
- MethodMatcher
- 总结
- 参考
前言
Spring AOP 同样也定义好几大族接口,以辅助 AOP 的实现,这章节我们来解析 Pointcut 接口
Pointcut ,切点。它是对 Joinpoint 的匹配点的抽象,可以理解为 Advice 通过 Pointcut 找到 Joinpoint
Pointcut
public interface Pointcut {// 类匹配ClassFilter getClassFilter();// 方法匹配MethodMatcher getMethodMatcher();// 匹配所有 Pointcut Pointcut TRUE = TruePointcut.INSTANCE;}
Pointcut
由 ClassFilter
和 MethodMatcher
组成
ClassFilter
@FunctionalInterface
public interface ClassFilter {// 给定类是否匹配boolean matches(Class<?> clazz);// 匹配所有类ClassFilter TRUE = TrueClassFilter.INSTANCE;}
ClassFilter
相对比较简单,主要提供 match
方法校验目标类是否匹配
AnnotationClassFilter
// 检查给定类是否包含指定注解
public class AnnotationClassFilter implements ClassFilter {// 目标注解private final Class<? extends Annotation> annotationType;// 是否检查父类private final boolean checkInherited;// .../*** 层级检查依赖方法 AnnotatedElementUtils#hasAnnotation* 非层级检查依赖方法 Class#isAnnotationPresent*/@Overridepublic boolean matches(Class<?> clazz) {return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(clazz, this.annotationType) :clazz.isAnnotationPresent(this.annotationType));}// ...}
- 常用的实现类
AnnotationClassFilter
,主要是基于注解匹配类 - 属性
checkInherited
决定是否检查上层类,分别基于方法AnnotatedElementUtils#hasAnnotation
和Class#isAnnotationPresent
AnnotationCandidateClassFilter
private static class AnnotationCandidateClassFilter implements ClassFilter {// 指定注解private final Class<? extends Annotation> annotationType;AnnotationCandidateClassFilter(Class<? extends Annotation> annotationType) {this.annotationType = annotationType;}// 依赖 AnnotationUtils#isCandidateClass:类、方法、属性上是否有指定注解@Overridepublic boolean matches(Class<?> clazz) {return AnnotationUtils.isCandidateClass(clazz, this.annotationType);}// ...}
一个常用的内部类实现,也是基于注解匹配,但是主要类、方法、属性任一含有目标注解就匹配,比如 @Async
注解
MethodMatcher
public interface MethodMatcher {// 静态匹配boolean matches(Method method, Class<?> targetClass);// true 动态 false 静态boolean isRuntime();// 动态匹配boolean matches(Method method, Class<?> targetClass, Object... args);// 匹配所有方法MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;}
MethodMatcher
主要区分两类:
静态匹配
,不会对方法的参数进行匹配动态匹配
,会同时匹配方法的参数,但不常用
主要看下静态相关实现
StaticMethodMatcher
public abstract class StaticMethodMatcher implements MethodMatcher {// 静态@Overridepublic final boolean isRuntime() {return false;}// 因为是静态,所以动态匹配方法 UnsupportedOperationException@Overridepublic final boolean matches(Method method, Class<?> targetClass, Object... args) {throw new UnsupportedOperationException("Illegal MethodMatcher usage");}}
静态抽象基类,isRuntime
返回 false
,动态匹配方法调用抛出 UnsupportedOperationException
异常,主要聚焦于 matches(Method method, Class<?> targetClass)
方法的实现
AnnotationMethodMatcher
public class AnnotationMethodMatcher extends StaticMethodMatcher {// 目标注解private final Class<? extends Annotation> annotationType;// 是否检查层级private final boolean checkInherited;// ...@Overridepublic boolean matches(Method method, Class<?> targetClass) {// 先进行一次快速匹配if (matchesMethod(method)) {return true;}// 忽略代理类,因为代理类没有注解信息if (Proxy.isProxyClass(targetClass)) {return false;}// 假设是接口方法,尝试获取实现类方法Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);// 如果获取到了再匹配一次return (specificMethod != method && matchesMethod(specificMethod));}// 根据 checkInherited 区分是否需要检查父类方法private boolean matchesMethod(Method method) {return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) :method.isAnnotationPresent(this.annotationType));}// ...}
- 跟
AnnotationClassFilter
对应的,AnnotationMethodMatcher
基于注解进行方法匹配 - 同样的,属性
checkInherited
决定是否层级匹配
StaticMethodMatcherPointcut
/*** 首先是一个 MethodMatcher,同时是一个 Pointcut,这样就可以拓展出* ClassFilter 的能力了,值得学习*/
public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {private ClassFilter classFilter = ClassFilter.TRUE;// 允许指定一个 ClassFilter,拓展出了 ClassFilter 的能力public void setClassFilter(ClassFilter classFilter) {this.classFilter = classFilter;}@Overridepublic ClassFilter getClassFilter() {return this.classFilter;}// 自己就是个 MethodMatcher@Overridepublic final MethodMatcher getMethodMatcher() {return this;}}
- 挺值得学习的设计模式,类似一种组合,跟
MethodBeforeAdviceInterceptor
的设计类似,StaticMethodMatcherPointcut
本身是个MethodMatcher
,实现Pointcut
又拓展出了ClassFilter
的能力,这样子类只要专注实现MethodMatcher
的方法就好 setClassFilter
方法支持设置指定的ClassFilter
NameMatchMethodPointcut
public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {// 匹配模板private List<String> mappedNames = new ArrayList<>();public void setMappedName(String mappedName) {setMappedNames(mappedName);}public void setMappedNames(String... mappedNames) {this.mappedNames = new ArrayList<>(Arrays.asList(mappedNames));}// 添加模板方法public NameMatchMethodPointcut addMethodName(String name) {this.mappedNames.add(name);return this;}// 静态匹配,equals 或者正则匹配@Overridepublic boolean matches(Method method, Class<?> targetClass) {for (String mappedName : this.mappedNames) {if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {return true;}}return false;}// 支持形如 "xxx*", "*xxx" 的正则匹配protected boolean isMatch(String methodName, String mappedName) {return PatternMatchUtils.simpleMatch(mappedName, methodName);}// 略
}
在 StaticMethodMatcherPointcut
的基础上,支持基于方法名匹配,同时支持形如 xxx*
, *xxx
的模糊匹配,比如*Service
匹配所有 Serivce
结尾的方法
demo
@My
public class A {public void aaa() {}public void bbb() {}
}public class B {public void aaa() {}
} public class NameMatchMethodTest {public static void main(String[] args) {NameMatchMethodPointcut matchMethodPointcut= new NameMatchMethodPointcut();matchMethodPointcut.setClassFilter(new AnnotationClassFilter(My.class));matchMethodPointcut.setMappedName("*a");if (matchMethodPointcut.getClassFilter().matches(A.class)) {for (Method m : A.class.getDeclaredMethods()) {boolean match = matchMethodPointcut.matches(m, A.class);System.out.println("A类的方法" + m.getName() + (match ? " 匹配" : " 不匹配"));}} else {System.out.println("A类不匹配");}if (matchMethodPointcut.getClassFilter().matches(B.class)) {for (Method m : B.class.getDeclaredMethods()) {boolean match = matchMethodPointcut.matches(m, B.class);System.out.println("B类的方法" + m.getName() + (match ? " 匹配" : " 不匹配"));}} else {System.out.println("B类不匹配");}}
}// 结果
A类的方法aaa 匹配
A类的方法bbb 不匹配
B类不匹配
StaticMethodMatcherPointcutDemo
public class StaticMethodMatcherPointcutDemo extends StaticMethodMatcherPointcut {@Overridepublic boolean matches(Method method, Class<?> targetClass) {return "a".equals(method.getName());}public void a() {}public void b() {}@Testpublic void test() throws NoSuchMethodException {StaticMethodMatcherPointcutDemo demo = new StaticMethodMatcherPointcutDemo();demo.setClassFilter(clazz -> clazz == StaticMethodMatcherPointcutDemo.class);boolean a = demo.matches(StaticMethodMatcherPointcutDemo.class.getMethod("a"), StaticMethodMatcherPointcutDemo.class);System.out.println(a); // trueboolean b = demo.matches(StaticMethodMatcherPointcutDemo.class.getMethod("b"), StaticMethodMatcherPointcutDemo.class);System.out.println(b); // false}
}
自己实现一个 StaticMethodMatcherPointcut
加深印象
ComposablePointcut
Composable
(可组合的)的 Pointcut
,提供了 union(并集)
intersection(交集)
等方法,而且还支持链式调用,设计思想值得学习
demo
@Deprecatedpublic static class Sample {@Autowiredpublic void a() {}// @After("")public void b() {}}@Testpublic void test() throws NoSuchMethodException {AnnotationMatchingPointcut annotationMatchingPointcut= new AnnotationMatchingPointcut(Deprecated.class, After.class, false);ComposablePointcut union = new ComposablePointcut(annotationMatchingPointcut).union(new AnnotationMethodMatcher(Autowired.class));Method a = Sample.class.getMethod("a");Method b = Sample.class.getMethod("b");// trueSystem.out.println(union.getMethodMatcher().matches(a, String.class));// falseSystem.out.println(union.getMethodMatcher().matches(b, String.class));}
AspectJExpressionPointcut
这个类比较复杂也比较重要,它的主要功能可以根据类名理解:基于 AspectJ
表达式的 Pointcut
同时它也是 ClassFilter
MethodMatcher
,对于类和方法的匹配都是基于 org.aspectj.weaver.tools
下的原生类来实现的
写个 demo
演示一下
public class AService implements A {public void a() {}
}public class BService implements B {public void b() {}
}public class Test2 {@Testpublic void test1() {AspectJExpressionPointcut aspectJExpressionPointcut= new AspectJExpressionPointcut();aspectJExpressionPointcut.setExpression("execution(* a())");System.out.println("A类:" + aspectJExpressionPointcut.matches(AService.class));System.out.println("B类:" + aspectJExpressionPointcut.matches(BService.class));System.out.println("================================");for (Method m : AService.class.getDeclaredMethods()) {System.out.println(m.getName() + ": " +aspectJExpressionPointcut.matches(m, m.getDeclaringClass()));}System.out.println("================================");for (Method m : BService.class.getDeclaredMethods()) {System.out.println(m.getName() + ": " +aspectJExpressionPointcut.matches(m, m.getDeclaringClass()));}}
}// 结果
A类:true
B类:true
================================
a: true
================================
b: false
类图
Pointcut
ClassFilter
MethodMatcher
总结
这一章节涉及的类比较多一点,主要对 Pointcut 体系抽象做了整体的了解,它可以与 ClassFilter 和 MethodMatcher 组合,来实现对类、方法的匹配
其中 AspectJExpressionPointcut 就是对基于注解的 AspectJ 的 切点表达式 的匹配实现
下一章节,了解下 Spring 下的 Advisor 抽象
上一篇:【源码】Spring AOP 3 Joinpoint
下一篇:【源码】Spring AOP 5 Advisor
参考
【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)
【源码】Spring AOP 4 Pointcut相关推荐
- 【Spring源码】AOP切面源码
[Spring源码]AOP切面源码 关键词 后置处理器BeanPostProcessor后置方法:applyBeanPostProcessorsAfterInitialization() 切面后置处理 ...
- 【老王读Spring AOP-3】Spring AOP 执行 Pointcut 对应的 Advice 的过程
Spring AOP 执行 Pointcut 对应的 Advice 的过程 前言 版本约定 正文 jdk proxy 是如何执行 Pointcut 对应的 Advice 的? 获取 Advice 链的 ...
- Spring AOP之PointCut详解
一.PointCut接口 /** Copyright 2002-2012 the original author or authors.** Licensed under the Apache Lic ...
- Spring AOP切入点@Pointcut -- execution表达式
Spring AOP 切入点@Pointcut – execution表达式 表达式示例 execution(* com.sample.service.impl..*.*(..)) 详述: execu ...
- 【栖梧-源码-spring】@Bean从解析到注册到beanDefinitionMap
[栖梧-源码-spring]@Bean从解析到注册到beanDefinitionMap 序幕 源码阅读技巧 本文说明 类 ConfigurationClassParser#doProcessConfi ...
- Spring AOP中pointcut 切点详解
Spring AOP中pointcut 是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的. Pointcut可以有下列方 ...
- Spring AOP中Pointcut,dvice 和 Advisor三个概念
Spring AOP中Pointcut,dvice 和 Advisor三个概念介绍 在理解了Spring的AOP后,需要重点理解的三个概念是:Pointcut Advice Advisor ...
- spring aop中pointcut表达式
spring aop中pointcut表达式 本文主要介绍spring aop中9种切入点表达式的写法 execute within this target args @target @within ...
- Spring AOP源码解析——AOP动态代理原理和实现方式
2019独角兽企业重金招聘Python工程师标准>>> Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和 ...
最新文章
- php自定义扩展函数,Laravel框架中扩展函数、扩展自定义类的方法
- 进大厂全靠自学,微软amp;头条实习生现身说法:我是这样自学深度学习的丨课程传送门...
- 打开电脑的组策略编辑器-计算机配置→管理模板下怎么没有网络,我应该怎么做才能通过FireWire卡屏幕播放?...
- 【阅读】所谓情商高,就是会说话
- css的img移上去边框效果及CSS透明度
- 蚂蚁集团回应两地暂缓上市;​iPhone 有望采用侧面指纹识别;Pyston v2 发布|极客头条
- php array函数 array_sum 求数组所有值和
- VB.NET/C# Free Grid Control 免费开源表格控件 - ReoGrid 介绍(1)
- 必备!最全电路基础知识讲解!
- 硬核干货 | 人脸识别的原理是什么?
- 如何通俗易懂地理解递归
- VBA批量OCR识别提取身份证照片信息_OCR车牌识别系统实现停车场智能停车管理
- 网页版在线公式编辑器
- 北京地铁,4号线换乘13号线,用时最短换乘线路
- 为什么很多人喜欢猫不喜欢狗
- 学校计算机房的布线注意要点,计算机机房布线的注意事项
- 在vue中使用Echarts的3D柱状图
- 【c#】键盘事件(keypress keydown keyup)
- 上海市“专精特新”中小企业认定
- 黑马程序员mysql答案_干货|MySQL常见问题及答案汇总