【源码】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;}

PointcutClassFilterMethodMatcher 组成

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#hasAnnotationClass#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 体系抽象做了整体的了解,它可以与 ClassFilterMethodMatcher 组合,来实现对类、方法的匹配

其中 AspectJExpressionPointcut 就是对基于注解的 AspectJ切点表达式 的匹配实现

下一章节,了解下 Spring 下的 Advisor 抽象

上一篇:【源码】Spring AOP 3 Joinpoint
下一篇:【源码】Spring AOP 5 Advisor

参考

【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)

【源码】Spring AOP 4 Pointcut相关推荐

  1. 【Spring源码】AOP切面源码

    [Spring源码]AOP切面源码 关键词 后置处理器BeanPostProcessor后置方法:applyBeanPostProcessorsAfterInitialization() 切面后置处理 ...

  2. 【老王读Spring AOP-3】Spring AOP 执行 Pointcut 对应的 Advice 的过程

    Spring AOP 执行 Pointcut 对应的 Advice 的过程 前言 版本约定 正文 jdk proxy 是如何执行 Pointcut 对应的 Advice 的? 获取 Advice 链的 ...

  3. Spring AOP之PointCut详解

    一.PointCut接口 /** Copyright 2002-2012 the original author or authors.** Licensed under the Apache Lic ...

  4. Spring AOP切入点@Pointcut -- execution表达式

    Spring AOP 切入点@Pointcut – execution表达式 表达式示例 execution(* com.sample.service.impl..*.*(..)) 详述: execu ...

  5. 【栖梧-源码-spring】@Bean从解析到注册到beanDefinitionMap

    [栖梧-源码-spring]@Bean从解析到注册到beanDefinitionMap 序幕 源码阅读技巧 本文说明 类 ConfigurationClassParser#doProcessConfi ...

  6. Spring AOP中pointcut 切点详解

    Spring AOP中pointcut 是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的. Pointcut可以有下列方 ...

  7. Spring AOP中Pointcut,dvice 和 Advisor三个概念

    Spring  AOP中Pointcut,dvice 和 Advisor三个概念介绍 在理解了Spring的AOP后,需要重点理解的三个概念是:Pointcut    Advice   Advisor ...

  8. spring aop中pointcut表达式

    spring aop中pointcut表达式 本文主要介绍spring aop中9种切入点表达式的写法 execute within this target args @target @within ...

  9. Spring AOP源码解析——AOP动态代理原理和实现方式

    2019独角兽企业重金招聘Python工程师标准>>> Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和 ...

最新文章

  1. php自定义扩展函数,Laravel框架中扩展函数、扩展自定义类的方法
  2. 进大厂全靠自学,微软amp;头条实习生现身说法:我是这样自学深度学习的丨课程传送门...
  3. 打开电脑的组策略编辑器-计算机配置→管理模板下怎么没有网络,我应该怎么做才能通过FireWire卡屏幕播放?...
  4. 【阅读】所谓情商高,就是会说话
  5. css的img移上去边框效果及CSS透明度
  6. 蚂蚁集团回应两地暂缓上市;​iPhone 有望采用侧面指纹识别;Pyston v2 发布|极客头条
  7. php array函数 array_sum 求数组所有值和
  8. VB.NET/C# Free Grid Control 免费开源表格控件 - ReoGrid 介绍(1)
  9. 必备!最全电路基础知识讲解!
  10. 硬核干货 | 人脸识别的原理是什么?
  11. 如何通俗易懂地理解递归
  12. VBA批量OCR识别提取身份证照片信息_OCR车牌识别系统实现停车场智能停车管理
  13. 网页版在线公式编辑器
  14. 北京地铁,4号线换乘13号线,用时最短换乘线路
  15. 为什么很多人喜欢猫不喜欢狗
  16. 学校计算机房的布线注意要点,计算机机房布线的注意事项
  17. 在vue中使用Echarts的3D柱状图
  18. 【c#】键盘事件(keypress keydown keyup)
  19. 上海市“专精特新”中小企业认定
  20. 黑马程序员mysql答案_干货|MySQL常见问题及答案汇总

热门文章

  1. Java复习十:集合的使用
  2. 量子计算 10 隐变量、贝尔不等式与CHSH
  3. 膜拜!华为大牛透彻讲解Java面试题100道必考题
  4. linux(centos7) 关机命令重启命令
  5. python获取日期
  6. java倒计时跳出窗口_java 窗口 倒计时 关闭
  7. js室内地图开发_室内地图JavaScript SDK地图控制 - 蜂鸟云
  8. Python itchat 微信推送消息至指定群聊或个人
  9. BIMServer1.5.88服务器部署及IFC文件上传并3D显示
  10. 庄懂着色器_L05_镜面反射