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

一、前言

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

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

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

二、动态代理技术说明

  • JDK动态代理:JDK原生的实现方式,需要被代理的目标类必须实现接口!它会根据目标类的接口动态生成一个代理对象!代理对象和目标对象有相同的接口!(拜把子)

  • CGLIB:通过继承被代理的目标类实现代理,所以不需要目标类实现接口!(认干爹)

<!-- 开启aspect注解的支持,proxy-target-class表示选择动态代理的方式,true表示使用CGLIB代理,false表示使用JDK动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

三、AOP 术语说明

横切关注点:从每个方法中抽取出来的同一类非核心业务。
前置通知、
通知 (Advice): 每一个横切关注点上要做的事情都需要写一个方法来实现。通知的类型有:前置通知、返回通知、异常通知、后置通知、环绕通知。

连接点 (Joint Point):指那些被拦截到的点。在Spring中,可以被动态代理拦截目标类的方法。

切入点 (Pointcut):定位连接点的方式,是一个表达式。符合条件的每一个方法都是一个具体的连接点。

切面 (Aspect):切入点和通知的结合,是一个类。

目标(target):被代理的目标对象。

代理 (proxy):向目标对象应用通知之后创建的代理对象。

织入 (weaving): 把通知应用到目标上,生成代理对象的过程。可以在编译期织入,也可以在运行期织入,Spring采用后者。

四、通知类型介绍

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

注解描述说明
@Before在被代理的目标方法前执行不能阻止业务模块的执行,除非通知方法抛出异常
@AfterReturning在被代理的目标方法成功结束后执行-
@AfterThrowing在被代理的目标方法异常结束后执行-
@After在被代理的目标方法最终结束后执行无论业务模块是否抛出异常,都会执行
@Around使用try…catch…finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置封装后由通知方法调用暴露的proceed()方法,去执行目标方法

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

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

五、切点表达式简介

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

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

@AspectJ 支持三种通配符:

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

逻辑运算符:

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

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

七、切点表达式

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

语法:

args(param-pattern)
  • param-pattern:参数类型,全路径的

示例:

@Pointcut("args(java.lang.String)")
public void stringParams() {}

(2)@args() 限制连接点匹配参数由指定注解标注的执行方法

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

语法:

@args(annotation-type)

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?)
  • modifiers-pattern:方法的可见性修饰符,如 public,protected,private;
  • ret-type-pattern:方法的返回值类型,如 int,void 等;
  • declaring-type-pattern:方法所在类的全路径名,如 com.spring.Aspect;
  • name-pattern:方法名,如 getOrderDetail();
  • param-pattern:方法的参数类型,如 java.lang.String;
  • throws-pattern:方法抛出的异常类型,如 java.lang.Exception;

示例:

// 匹配目标类的所有 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)
  • 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)
  • annotation-type:注解类型,全路径的

示例:

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

@Pointcut("@within(org.springframework.stereotype.Repository)")

(9)@annotation() 限制匹配带有指定注解连接点

指定注解标注的方法

语法:

@annotation(annotation-type)
  • annotation-type:注解类型,全路径的

示例:

@Pointcut("@annotation(com.test.annotations.LogAuto)")
  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值