在文章Spring AOP之术语简介中有提到,pointcut定义了一种模式,用于匹配join point。Spring AOP中使用了AspectJ的pointcut模式定义语言。

声明一个pointcut

一个pointcut由两部分组成:

  • Pointcut signature:pointcut签名,类似于方法签名,但该方法返回值必须是void
  • Pointcut expression:@Pointcut注解中的模式定义表达式
@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature

pointcut expression指示符

pointcut expression指示符用来指示该表达式的目的,Spring AOP支持以下10种指示符:

  • execution:匹配指定方法。
execution(public * *(..))    //任意public方法
execution(* set*(..))   //任意名称以set开头的方法
execution(* com.xyz.service.AccountService.*(..))   //com.xyz.service.AccountService接口中定义的任意方法
execution(* com.xyz.service.*.*(..))    //com.xyz.service包中定义的任意方法
execution(* com.xyz.service..*.*(..))   //com.xyz.service包中及其子包中定义的任意方法
  • within:匹配指定类内的所有join point(在Spring AOP中仅是方法执行点)。
within(com.xyz.service.*)    //com.xyz.service包中的任意方法
within(com.xyz.service..*)  //com.xyz.service包中及其子包中的任意方法
  • this:匹配可以向上转型为this指定的类型的代理对象中的所有join point(在Spring AOP中仅是方法执行点)。
this(com.xyz.service.AccountService) //实现了com.xyz.service.AccountService接口的代理类中的所有方法
  • target:匹配可以向上转型为target指定的类型的目标对象中的所有join point(在Spring AOP中仅是方法执行点)。
target(com.xyz.service.AccountService)   //实现了com.xyz.service.AccountService接口的目标类中的所有方法
thistarget的区别究竟在哪呢?举例说明。

下述所有类均定义在包com.qyh.test.aspectj中。

  • 定义一个接口TargetClassInterface
public interface TargetClassInterface {void sayHello();
}
  • 定义一个TargetClassInterface接口的实现类TargetClass
@Component("targetClass")
public class TargetClass implements TargetClassInterface {@Overridepublic void sayHello() {System.out.println("Hello World!");}
}
  • 定义Spring的Java配置类AppConfig
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {}
  • 定义切面类AspectClass
@Component
@Aspect
public class AspectClass {@Pointcut("this(com.qyh.test.aspectj.TargetClass)")public void pointCutInTargetClass() {}@Before("pointCutInTargetClass()")public void beforeAdvice() {System.out.println("我是前置增强");}
}
  • 定义测试类Test
public class Test {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);TargetClassInterface targetClass = applicationContext.getBean("targetClass", TargetClassInterface.class);targetClass.sayHello();}
}
  • 测试结果1
Hello World!
  • 将切面类AspectClass修改如下
@Component
@Aspect
public class AspectClass {@Pointcut("target(com.qyh.test.aspectj.TargetClass)")public void pointCutInTargetClass() {}@Before("pointCutInTargetClass()")public void beforeAdvice() {System.out.println("我是前置增强");}
}
  • 测试结果2
我是前置增强
Hello World!
  • 结果分析
    由于Spring AOP默认使用的是JDK的动态代理来为接口生成代理对象,其代理对象实现了接口TargetClassInterface,与TargetClass没有关系,使用this关键字时,该代理对象无法向上转型为TargetClass,因此该切面失效,没有应用前置增强。使用target关键字时,目标对象可以向上转型为TargetClass(目标对象本身就是TargetClass),因此该切面生效,应用前置增强。

  • args:用方法参数去匹配方法

args(java.io.Serializable)   //只有一个参数,且参数的运行时类型是java.io.Serializable的方法
args(java.io.Serializable)execution(* *(java.io.Serializable))的在哪呢?举例说明。

下述所有类均定义在包com.qyh.test.aspectj中。

  • 定义一个目标类TargetClass
@Component("targetClass")
public class TargetClass {public void originalMethod(String name, int age) {System.out.println("我的名字叫" + name + ",我今年" + age + "岁了!");}public String sayHello(Serializable name) throws Exception {return "Hello World!" + name;}
}
  • 定义Spring的Java配置类AppConfig
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {}
  • 定义切面类AspectClass
@Component
@Aspect
public class AspectClass {@Pointcut("execution(* *(java.io.Serializable))")public void pointCutInTargetClass1() {}@Pointcut("args(java.lang.String)")public void pointCutInTargetClass2() {}@Before("pointCutInTargetClass1()")public void beforeAdvice() {System.out.println("我是前置增强");}@AfterReturning(value = "pointCutInTargetClass2()")public void afterReturningAdvice() {System.out.println("我是后置增强");}
}
  • 定义测试类Test
public class Test {public static void main(String[] args) throws Exception {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);TargetClass targetClass = applicationContext.getBean("targetClass", TargetClass.class);System.out.println(targetClass.sayHello("小钱"));}
}
  • 测试结果
我是前置增强
我是后置增强
Hello World!小钱
  • 结果分析
    在本例中,sayHello(java.io.Serializable)方法的参数声明类型是java.io.Serializable,运行时类型是java.lang.String,因此execution(* *(java.io.Serializable))args(java.lang.String)均能对该方法进行增强。这个例子说明args(java.io.Serializable)execution(* *(java.io.Serializable))是不一样的。args(java.io.Serializable)指参数的运行时类型是java.io.Serializable,而execution(* *(java.io.Serializable))指参数的声明类型是java.io.Serializable

  • @target:Limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type.

@target(org.springframework.transaction.annotation.Transactional)   //Any join point (method execution only in Spring AOP) where the target object has a @Transactional annotation
  • @within:Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP).
@within(org.springframework.transaction.annotation.Transactional)   //Any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation
@target@within的区别究竟在哪呢?举例说明。

下述所有类均定义在包com.qyh.test.aspectj.withinandtargetannotation中。

  • 定义两个注解类MyAnnotation1和MyAnnotation2
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface MyAnnotation1 {}@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface MyAnnotation2 {}
  • 定义3个实体类GrandFather、Father和Son
@MyAnnotation1
public class GrandFather {public void say() {System.out.println("GrandFather say");}public void run() {System.out.println("GrandFather run");}
}@MyAnnotation2
public class Father extends GrandFather {@Overridepublic void say() {System.out.println("Father say");}
}@Component
public class Son extends Father {@Overridepublic void say() {System.out.println("Son say");}
}
  • 定义Spring的Java配置类AppConfig
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {}
  • 定义切面类AspectClass
@Aspect
@Component
public class AspectClass {@Before("@within(com.qyh.test.aspectj.withinandtargetannotation.MyAnnotation1)")public void beforeAdviceWithinMyAnnotation1() {System.out.println("beforeAdviceWithinMyAnnotation1");}@Before("@within(com.qyh.test.aspectj.withinandtargetannotation.MyAnnotation2)")public void beforeAdviceWithinMyAnnotation2() {System.out.println("beforeAdviceWithinMyAnnotation2");}@Before("@target(com.qyh.test.aspectj.withinandtargetannotation.MyAnnotation1)")public void beforeAdviceTargetMyAnnotation1() {System.out.println("beforeAdviceTargetMyAnnotation1");}@Before("@target(com.qyh.test.aspectj.withinandtargetannotation.MyAnnotation2)")public void beforeAdviceTargetMyAnnotation2() {System.out.println("beforeAdviceTargetMyAnnotation2");}
}
  • 定义测试类Test
public class Test {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);GrandFather grandFather = applicationContext.getBean("grandFather", GrandFather.class);grandFather.say();grandFather.run();Father father = applicationContext.getBean("father", Father.class);father.say();father.run();Son son = applicationContext.getBean("son", Son.class);son.say();son.run();}
}
  • 测试结果
beforeAdviceTargetMyAnnotation1
beforeAdviceWithinMyAnnotation1
GrandFather say
beforeAdviceTargetMyAnnotation1
beforeAdviceWithinMyAnnotation1
GrandFather run
beforeAdviceTargetMyAnnotation2
beforeAdviceWithinMyAnnotation2
Father say
beforeAdviceTargetMyAnnotation2
beforeAdviceWithinMyAnnotation1
GrandFather run
Son say
beforeAdviceWithinMyAnnotation1
GrandFather run
  • 结果分析
    父类有注解A,子类没有注解,子类中不是在父类中定义的方法不会被@within(A)@target(A)拦截。
    父类有注解A,子类没有注解,子类中在父类中定义的方法会被@within(A)拦截,但不会被@target(A)拦截
    父类有注解A,子类有注解B,子类中不是在父类中定义的方法会被注解@within(B)@target(B)拦截,但不会被@within(A)@target(A)拦截。
    父类有注解A,子类有注解B,子类中在父类中定义的方法会被@within(A)@target(B)拦截,但不会被@within(B)@target(A)拦截。

  • @args:匹配方法,该方法的参数的运行时类型带有指定的注解

@args(com.xyz.security.Classified)  //只有一个参数,且该参数的运行时类型具有com.xyz.security.Classified注解的方法
  • @annotation:匹配方法,该方法带有指定的注解
@annotation(org.springframework.transaction.annotation.Transactional)   //被标注了org.springframework.transaction.annotation.Transactional注解的所有方法
  • bean:匹配bean实例内的所有join point(在Spring AOP中仅是方法执行点)。
bean(tradeService)   //id或name为tradeService的bean实例的所有方法
bean(*Service)  //id或name以Service结尾的bean实例的所有方法
指示符分类
  • Kinded designators:execution
  • Scoping designators:within
  • Contextual designators:thistarget@annotation
    其中,Kinded designators和Contextual designators的性能较差,而Scoping designators的性能最好,故在开发中应尽可能地使用within指示符来定义pointcut

pointcut expression表达式

通配符语法
  • *:匹配任何数量字符。
  • ..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
  • +:匹配指定类型的子类型,仅能作为后缀放在类型模式后边。
模式匹配语法

execution指示符为例:

execution(修饰符类型? 返回值类型 类型模式?方法名称(参数类型) 异常类型?)

References

Spring Framework 5.2.5 Reference Doc.
Spring–@within和@target的区别
02-05 AOP学习之@within和@target使用示例及对比分析

Spring AOP之pointcut语法相关推荐

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

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

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

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

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

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

  4. Spring AOP中pointcut 切点详解

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

  5. 【源码】Spring AOP 4 Pointcut

    [源码]Spring AOP 4 Pointcut 前言 Pointcut ClassFilter AnnotationClassFilter AnnotationCandidateClassFilt ...

  6. spring aop中pointcut表达式

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

  7. Spring AOP 切点(pointcut)表达式

    概括 这遍文章将介绍Spring AOP切点表达式(下称表达式)语言,首先介绍两个面向切面编程中使用到的术语. 连接点(Joint Point):广义上来讲,方法.异常处理块.字段这些程序调用过程中可 ...

  8. Spring AOP 切点 Pointcut 表达式介绍与使用

    一.前言 面向切面编程 AOP 是一种常见的编程思想,是面向对象编程的一种补充,AOP 框架通过修改源代码,将处理逻辑编织到指定的业务模块中 常见的处理比如:在方执行法前进行校验,在方法执行后进行日志 ...

  9. Spring AOP中@Pointcut切入点表达式详解

    目录 一.瞅一眼标准的AspectJ Aop的pointcut的表达式 二.SpringAop的十一种AOP表达式 三.演示使用 1.execution: 2.within: 3.this: 4.ta ...

最新文章

  1. Spring 容器AOP的实现原理——动态代理
  2. 小白入门深度学习 | 第三篇:30分钟入门深度学习 - TensorFlow版
  3. 插入顶部_轻巧的衣领插入技术
  4. cnn卷积神经网络应用_卷积神经网络(CNN):应用的核心概念
  5. 施一公获百万科学界大奖!科研大牛如何炼成?
  6. java spark读写hdfs文件,Spark1.4从HDFS读取文件运行Java语言WordCounts
  7. 语音识别已逐渐普及 搜狗讯飞各具特色
  8. java bridge 模式_学习:java设计模式—Bridge模式
  9. cuda安装及百度云链接
  10. ArcGIS小图斑根据相邻地类属性融合。
  11. 数据预测模型_如何根据已有数据得出预测模型?线性回归公式来帮你!
  12. UFS 3.1协议分析(第五章) -- UFS协议栈
  13. draft伦理——第七章
  14. 一篇博客解决网线挑选问题
  15. 验证手机号码 (包含166和199)
  16. Java面试题3(jsp)
  17. 碉堡的GitHub使用方式
  18. ib中文诗歌赏析:背后的文化意义
  19. 移动硬盘出现 文件目录损坏且无法读取 解决方法教程
  20. 数据集搜索引擎横空出现!数据是怎样放入数据科学中的?

热门文章

  1. 苹果计算机显示错误怎么按,当使用iTunes修复iPhone设备时出现4013的错误提示怎么办?...
  2. 【音视频数据数据处理 10】【PCM篇】将PCM转为WAV格式音频
  3. Word2016给英文添加段落编号的方法:有截图
  4. 化妆品行业 垂直电商
  5. Spring-Cloud-Config快速开始
  6. 使用CMD命令提示符配置IP
  7. 关于产品XDR产品系列(区别于EDR)
  8. 百度大数据实习生面试
  9. 毕设模板-目录的更新与格式设置
  10. matlab修图美白,用PS通道对头像照片祛斑美白修图的教程