Spring AOP之pointcut语法
在文章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接口的目标类中的所有方法
this
和target
的区别究竟在哪呢?举例说明。
下述所有类均定义在包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:
this
,target
和@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语法相关推荐
- Spring AOP切入点@Pointcut -- execution表达式
Spring AOP 切入点@Pointcut – execution表达式 表达式示例 execution(* com.sample.service.impl..*.*(..)) 详述: execu ...
- Spring AOP中Pointcut,dvice 和 Advisor三个概念
Spring AOP中Pointcut,dvice 和 Advisor三个概念介绍 在理解了Spring的AOP后,需要重点理解的三个概念是:Pointcut Advice Advisor ...
- 【老王读Spring AOP-3】Spring AOP 执行 Pointcut 对应的 Advice 的过程
Spring AOP 执行 Pointcut 对应的 Advice 的过程 前言 版本约定 正文 jdk proxy 是如何执行 Pointcut 对应的 Advice 的? 获取 Advice 链的 ...
- Spring AOP中pointcut 切点详解
Spring AOP中pointcut 是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的. Pointcut可以有下列方 ...
- 【源码】Spring AOP 4 Pointcut
[源码]Spring AOP 4 Pointcut 前言 Pointcut ClassFilter AnnotationClassFilter AnnotationCandidateClassFilt ...
- spring aop中pointcut表达式
spring aop中pointcut表达式 本文主要介绍spring aop中9种切入点表达式的写法 execute within this target args @target @within ...
- Spring AOP 切点(pointcut)表达式
概括 这遍文章将介绍Spring AOP切点表达式(下称表达式)语言,首先介绍两个面向切面编程中使用到的术语. 连接点(Joint Point):广义上来讲,方法.异常处理块.字段这些程序调用过程中可 ...
- Spring AOP 切点 Pointcut 表达式介绍与使用
一.前言 面向切面编程 AOP 是一种常见的编程思想,是面向对象编程的一种补充,AOP 框架通过修改源代码,将处理逻辑编织到指定的业务模块中 常见的处理比如:在方执行法前进行校验,在方法执行后进行日志 ...
- Spring AOP中@Pointcut切入点表达式详解
目录 一.瞅一眼标准的AspectJ Aop的pointcut的表达式 二.SpringAop的十一种AOP表达式 三.演示使用 1.execution: 2.within: 3.this: 4.ta ...
最新文章
- Spring 容器AOP的实现原理——动态代理
- 小白入门深度学习 | 第三篇:30分钟入门深度学习 - TensorFlow版
- 插入顶部_轻巧的衣领插入技术
- cnn卷积神经网络应用_卷积神经网络(CNN):应用的核心概念
- 施一公获百万科学界大奖!科研大牛如何炼成?
- java spark读写hdfs文件,Spark1.4从HDFS读取文件运行Java语言WordCounts
- 语音识别已逐渐普及 搜狗讯飞各具特色
- java bridge 模式_学习:java设计模式—Bridge模式
- cuda安装及百度云链接
- ArcGIS小图斑根据相邻地类属性融合。
- 数据预测模型_如何根据已有数据得出预测模型?线性回归公式来帮你!
- UFS 3.1协议分析(第五章) -- UFS协议栈
- draft伦理——第七章
- 一篇博客解决网线挑选问题
- 验证手机号码 (包含166和199)
- Java面试题3(jsp)
- 碉堡的GitHub使用方式
- ib中文诗歌赏析:背后的文化意义
- 移动硬盘出现 文件目录损坏且无法读取 解决方法教程
- 数据集搜索引擎横空出现!数据是怎样放入数据科学中的?