其他分享
首页 > 其他分享> > Spring AOP 切点 Pointcut 表达式介绍与使用

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

作者:互联网

一、前言

面向切面编程 AOP 是一种常见的编程思想,是面向对象编程的一种补充,AOP 框架通过修改源代码,将处理逻辑编织到指定的业务模块中

常见的处理比如:在方执行法前进行校验,在方法执行后进行日志的记录,事务管理,消息通知,业务监控等。

本篇主要介绍 Aspectj 通过注解配置,切点表达式的书写

二、AOP 术语说明

通知 (Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。通知的类型有:后置通知、返回通知、异常通知、环绕通知、前置通知。

连接点 (Joint Point):连接点满足切入点识别,是在应用执行过程中能够插入切面(Aspect)的一个点。广义上来讲,方法、异常处理块、字段这些程序调用过程中可以抽像成一个执行步骤(或者说执行点)的单元。可以是调用方法时、甚至修改一个字段时。

切入点 (Pointcut):切入点是特定连接点的描述定义,是指通知(Advice)所要织入(Weaving)的具体位置;Spring AOP 通过切入点来定位到哪些连接点。切点表达式语言就是切点用来定义连接点的语法。

切面 (Aspect):切面是通知和切入点的结合,通知规定了在什么时机干什么事,切入点规定了在什么位置。

引入 (Introduction):引入允许我们向现有的类添加新的方法或者属性。

织入 (weaving): 织入是把切面应用到目标对象并创建代理对象的过程。切点在指定的连接点(切点)被织入到目标对象中。在目标的生命周期中,织入的时机有多种:编译期、类加载期、运行期

三、通知类型介绍

Spring AOP 中现有方法进行增强处理有 5 中通知类型,分别是:

注解描述说明
@Before通知方法会在目标方法调用之前调用不能阻止业务模块的执行,除非通知方法抛出异常
@AfterReturning通知方法会在目标方法返回后调用-
@AfterThrowing通知方法会在目标方法异常后调用-
@After通知方法会在目标方法返回或异常后调用无论业务模块是否抛出异常,都会执行
@Around通知方法会将目标方法封装起来封装后由通知方法通过调用暴露的 proceed() 方法,去执行目标方法

以上五种通知类型可以对现有方法进行增强处理。

如果需要对现有类增加新的方法,可以通过 @DeclareParents 注解可以实现,DeclareParents 是一种 引入 (Introduction ) 类型的模型,在属性声明上使用,主要用于为指定的业务模块添加新的接口和相应的实现。

四、切点表达式简介

切点指示器描述
arg()限制连接点匹配参数为指定类型的执行方法
@args()限制连接点匹配参数由指定注解标注的执行方法
execution()用于匹配是连接点的执行方法
this()限制连接点匹配 AOP 代理的 Bean 应用为指定类型的类
target()限制连接点匹配目标对象为指定类型的类
@target()限制连接点匹配特点的执行对象,这些对象对应的类要具备指定类型的注解
within()限制连接点匹配特点的执行对象,这些对象对应的类要具备指定类型的注解
@within()限制连接点匹配指定注解所标注的类型(当使用 Spring AOP 时,方法定义在由指定的注解所标注的类里)
@annotation()限制匹配带有指定注解连接点

五、通配符合与逻辑运算符

@AspectJ 支持三种通配符:

符号描述
*匹配任意字符,只匹配一个元素
..匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使用
+表示按照类型匹配指定类的所有类,必须跟在类名后面,如 com.test.User+,表示继承该类的所有子类包括本身

逻辑运算符:

切点表达式由切点函数组成,切点函数之间还可以进行逻辑运算,组成复合切点。

符号描述xml 中表示
&&与操作符。相当于切点的交集运算。xml 配置文件中使用切点表达式,&是特殊字符,所以需要用 and 来表示
||或操作符。相当于切点的并集运算or
!非操作符,相当于切点的反集运算not

六、切点表达式

(1)arg() 限制连接点匹配参数为指定类型的执行方法

语法:

args(param-pattern)

示例:

@Pointcut("args(java.lang.String)")
public void stringParams() {}
(2)@args() 限制连接点匹配参数由指定注解标注的执行方法

这个指示符是用来匹配连接点的参数的,@args 指出连接点在运行时传过来的 参数的类必须要有指定的注解

语法:

@args(annotation-type)

示例:

// 参数 @Entity 注解的 bean 对象的方法
@Pointcut("@args(javax.persistence.Entity)")
public void methodsEntityParams() {}
(3)execution() 用于匹配是连接点的执行方法

Spring 切面粒度最小是达到方法级别,而 execution 表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的配置,所以是使用最广泛的。

语法:

// 问号 ? 表示该项可以没有
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

示例:

// 匹配目标类的所有 public 方法,第一个 * 代表返回类型,第二个 * 代表方法名,..代表方法的参数
execution(public * *(..))
// 匹配目标类所有以 User 为后缀的方法。第一个 * 代表返回类型,*User 代表以 User 为后缀的方法
execution(* *User(..))
// 匹配 User 类里的所有方法
execution(* com.test.demo.User.*(..))
// 匹配 User 类及其子类的所有方法
execution(* com.test.demo.User+.*(..)) :
// 匹配 com.test 包下的所有类的所有方法
execution(* com.test.*.*(..))
// 匹配 com.test 包下及其子孙包下所有类的所有方法
execution(* com.test..*.*(..)) :
// 匹配 getOrderDetail 方法,且第一个参数类型是 Long,第二个参数类型是 String
execution(* getOrderDetail(Long, String))
(4)this() 和 target()

this() 限制连接点匹配 AOP 代理的 Bean 应用为指定类型的类
target() 限制连接点匹配目标对象为指定类型的类

this 用来匹配的连接点所属的对象引用是某个特定类型的实例,target 用来匹配的连接点所属目标对象必须是指定类型的实例;那么这两个有什么区别呢?原来AspectJ在实现代理时有两种方式:

1、如果当前对象引用的类型没有实现自接口时,spring aop使用生成一个基于CGLIB的代理类实现切面编程
2、如果当前对象引用实现了某个接口时,Spring aop使用JDK的动态代理机制来实现切面编程

this指示符就是用来匹配基于CGLIB的代理类,通俗的来讲就是,如果当前要代理的类对象没有实现某个接口的话,则使用this;target指示符用于基于JDK动态代理的代理类,通俗的来讲就是如果当前要代理的目标对象有实现了某个接口的话,则使用target.:

public class FooDao implements BarDao {
    ...
}

比如在上面这段代码示例中,spring aop将使用jdk的动态代理来实现切面编程,在编写匹配这类型的目标对象的连接点表达式时要使用target指示符, 如下所示:

@Pointcut("target(org.test.dao.BarDao)")

如果 FooDao 类没有实现任何接口,或者在spring aop配置属性:proxyTargetClass设为true时,Spring Aop会使用基于CGLIB的动态字节码技为目标对象生成一个子类将为代理类,这时应该使用this指示器:

@Pointcut("this(org.test.dao.FooDao)")
(6)@target() 限制连接点匹配特点的执行对象,这些对象对应的类要具备指定类型的注解

这个指示器匹配指定连接点,这个连接点所属的目标对象的类有一个指定的注解:

语法:

@target(annotation-type)

示例:

@Pointcut("@target(org.springframework.stereotype.Repository)")
(7)within() 限制连接点匹配特点的执行对象,这些对象对应的类要具备指定类型的注解

within 表达式的粒度为类,其参数为全路径的类名(可使用通配符),表示匹配当前表达式的所有类都将被当前方法环绕。如下是 within 表达式的语法:

语法:

within(declaring-type-pattern)

示例:

within 表达式只能指定到类级别,如下示例表示匹配 com.spring.service.BusinessObject 中的所有方法:

within(com.spring.service.BusinessObject)

within 表达式路径和类名都可以使用通配符进行匹配,比如如下表达式将匹配 com.spring.service 包下的所有类,不包括子包中的类:

within(com.spring.service.*)

如下表达式表示匹配 com.spring.service 包及子包下的所有类:

within(com.spring.service..*)
(8)@within() 限制连接点匹配指定注解所标注的类型(当使用 Spring AOP 时,方法定义在由指定的注解所标注的类里)

@within表示匹配带有指定注解的类

语法:

@within(annotation-type)

示例:

如下所示示例表示匹配使用 org.springframework.stereotype.Repository 注解标注的类:

@Pointcut("@within(org.springframework.stereotype.Repository)")
(9)@annotation() 限制匹配带有指定注解连接点

指定注解标注的方法

语法:

@annotation(annotation-type)

示例:

@Pointcut("@annotation(com.test.annotations.LogAuto)")

标签:匹配,连接点,Spring,指定,切点,Pointcut,注解,方法
来源: https://blog.csdn.net/qq_40147863/article/details/117623562