首页 > 其他分享 >SpringAOP中的切点表达式Pointcut详解

SpringAOP中的切点表达式Pointcut详解

时间:2024-07-16 12:22:38浏览次数:13  
标签:匹配 service 切点 类型 Pointcut SpringAOP 注解 表达式

https://www.jb51.net/program/293999439.htm

 

一、概述

Spring AOP 只支持 Spring Bean 的方法切入,所以切点表达式只会匹配 Bean 类中的方法。

二、切点表达式配置

1. 内置配置

定义切面通知时,在 @Before 或 @AfterReturning 等通知注解中指定表达式。

1 2 3 4 5 6 7 8 @Aspect @Component public class DemoAspect {     @Before("execution(* cn.codeartist.spring.aop.advice.*.*(..))")     public void doBefore() {         // 自定义逻辑     } }

2. 注解配置

在切面类中,先定义一个方法并使用 @Pointcut 注解来指定表达式。

然后在定义切面通知时,在通知注解中指定定义表达式的方法签名。

1 2 3 4 5 6 7 8 9 10 11 12 @Aspect @Component public class DemoAspect {     @Pointcut("execution(* cn.codeartist.spring.aop.aspectj.*.*(..))")     private void pointcut() {         // 切点表达式定义方法,方法修饰符可以是private或public     }     @Before("pointcut()")     public void doBefore(JoinPoint joinPoint) {         // 自定义逻辑     } }

3. 公共配置

在任意类中,定义一个公共方法并使用 @Pointcut 注解来指定表达式。

1 2 3 4 5 6 public class CommonPointcut {     @Pointcut("execution(* cn.codeartist.aop.*..*(..))")     public void pointcut() {         // 注意定义切点的方法的访问权限为public     } }

在切面类中定义切面通知时,在通知注解中指定定义表达式的方法签名全路径。

1 2 3 4 5 6 7 8 @Aspect @Component public class DemoAspect {     @Before("cn.codeartist.aop.CommonPointcut.pointcut()")     public void commonPointcut() {         // 自定义逻辑     } }

三、切点表达式类型

Spring AOP 支持以下几种切点表达式类型。

execution

匹配方法切入点。根据表达式描述匹配方法,是最通用的表达式类型,可以匹配方法、类、包。

表达式模式:

1 execution(modifier? ret-type declaring-type?name-pattern(param-pattern) tdrows-pattern?)

表达式解释:

  • modifier:匹配修饰符,public, private 等,省略时匹配任意修饰符
  • ret-type:匹配返回类型,使用 * 匹配任意类型
  • declaring-type:匹配目标类,省略时匹配任意类型
    • .. 匹配包及其子包的所有类
  • name-pattern:匹配方法名称,使用 * 表示通配符
    • * 匹配任意方法
    • set* 匹配名称以 set 开头的方法
  • param-pattern:匹配参数类型和数量
    • () 匹配没有参数的方法
    • (..) 匹配有任意数量参数的方法
    • (*) 匹配有一个任意类型参数的方法
    • (*,String) 匹配有两个参数的方法,并且第一个为任意类型,第二个为 String 类型
  • tdrows-pattern:匹配抛出异常类型,省略时匹配任意类型

使用示例:

1 2 3 4 5 6 7 8 // 匹配public方法 execution(public * *(..)) // 匹配名称以set开头的方法 execution(* set*(..)) // 匹配AccountService接口或类的方法 execution(* com.xyz.service.AccountService.*(..)) // 匹配service包及其子包的类或接口 execution(* com.xyz.service..*(..))

witdin

匹配指定类型。匹配指定类的任意方法,不能匹配接口。

表达式模式:

1 witdin(declaring-type)

使用示例:

1 2 3 4 5 6 // 匹配service包的类 witdin(com.xyz.service.*) // 匹配service包及其子包的类 witdin(com.xyz.service..*) // 匹配AccountServiceImpl类 witdin(com.xyz.service.AccountServiceImpl)

tdis

匹配代理对象实例的类型,匹配在运行时对象的类型。

注意:基于 JDK 动态代理实现的 AOP,tdis 不能匹配接口的实现类,因为代理类和实现类并不是同一种类型

表达式模式:

1 tdis(declaring-type)

使用示例:

1 2 3 4 5 6 // 匹配代理对象类型为service包下的类 tdis(com.xyz.service.*) // 匹配代理对象类型为service包及其子包下的类 tdis(com.xyz.service..*) // 匹配代理对象类型为AccountServiceImpl的类 tdis(com.xyz.service.AccountServiceImpl)

target

匹配目标对象实例的类型,匹配 AOP 被代理对象的类型。

表达式模式:

1 target(declaring-type)

使用示例:

1 2 3 4 5 6 // 匹配目标对象类型为service包下的类 target(com.xyz.service.*) // 匹配目标对象类型为service包及其子包下的类 target(com.xyz.service..*) // 匹配目标对象类型为AccountServiceImpl的类 target(com.xyz.service.AccountServiceImpl)

三种表达式匹配范围如下:

表达式匹配范围 witdin tdis target
接口
实现接口的类
不实现接口的类

args

匹配方法参数类型和数量,参数类型可以为指定类型及其子类。

使用 execution 表达式匹配参数时,不能匹配参数类型为子类的方法。

表达式模式:

1 args(param-pattern)

使用示例:

1 2 3 4 // 匹配参数只有一个且为Serializable类型(或实现Serializable接口的类) args(java.io.Serializable) // 匹配参数个数至少有一个且为第一个为Example类型(或实现Example接口的类) args(cn.codeartist.spring.aop.pointcut.Example,..)

bean

通过 bean 的 id 或名称匹配,支持 * 通配符。

表达式模式:

1 bean(bean-name)

使用示例:

1 2 3 4 // 匹配名称以Service结尾的bean bean(*Service) // 匹配名称为demoServiceImpl的bean bean(demoServiceImpl)

@witdin

匹配指定类型是否含有注解。当定义类时使用了注解,该类的方法会被匹配,但在接口上使用注解不匹配。

使用示例:

1 2 // 匹配使用了Demo注解的类 @within(cn.codeartist.spring.aop.pointcut.Demo)

@target

匹配目标对象实例的类型是否含有注解。当运行时对象实例的类型使用了注解,该类的方法会被匹配,在接口上使用注解不匹配。

使用示例:

1 2 // 匹配对象实例使用了Demo注解的类 @target(cn.codeartist.spring.aop.pointcut.Demo)

@annotation

匹配方法是否含有注解。当方法上使用了注解,该方法会被匹配,在接口方法上使用注解不匹配。

使用示例:

1 2 // 匹配使用了Demo注解的方法 @annotation(cn.codeartist.spring.aop.pointcut.Demo)

@args

匹配方法参数类型是否含有注解。当方法的参数类型上使用了注解,该方法会被匹配。

使用示例:

1 2 3 4 // 匹配参数只有一个且参数类使用了Demo注解 @args(cn.codeartist.spring.aop.pointcut.Demo) // 匹配参数个数至少有一个且为第一个参数类使用了Demo注解 @args(cn.codeartist.spring.aop.pointcut.Demo,..)

切点表达式的参数匹配

切点表达式中的参数类型,可以和通知方法的参数通过名称绑定,表达式中不需要写类或注解的全路径,而且能直接获取到切面拦截的参数或注解信息。

1 2 3 4 5 6 7 8 @Before("pointcut() && args(name,..)") public void doBefore(String name) {     // 切点表达式增加参数匹配,可以获取到name的信息 } @Before("@annotation(demo)") public void doBefore(Demo demo) {     // 这里可以直接获取到Demo注解的信息 }

切点表达式的参数匹配同样适用于 @witdin, @target, @args

怎样编写一个好的切点表达式?

要使切点的匹配性能达到最佳,编写表达式时,应该尽可能缩小匹配范围,切点表达式分为三大类:

  • 类型表达式:匹配某个特定切入点,如 execution
  • 作用域表达式:匹配某组切入点,如 witdin
  • 上下文表达式:基于上下文匹配某些切入点,如 tdis、target 和 @annotation

一个好的切点表达式应该至少包含前两种(类型和作用域)类型。 作用域表达式匹配的性能非常快,所以表达式中尽可能使用作用域类型。

上下文表达式可以基于切入点上下文匹配或在通知中绑定上下文。 单独使用类型表达式或上下文表达式比较消耗性能(时间或内存使用)。

四、切点表达式组合

使用 &&、|| 和 ! 来组合多个切点表达式,表示多个表达式“与”、“或”和“非”的逻辑关系。

这可以用来组合多种类型的表达式,来提升匹配效率。

1 2 3 4 5 // 匹配doExecution()切点表达式并且参数第一个为Account类型的方法 @Before("doExecution() && args(account,..)") public void validateAccount(Account account) {     // 自定义逻辑 }

五、附录

1. @Pointcut 指定切点表达式

2. 切点表达式类型

表达式类型 描述
execution 匹配方法切入点
within 匹配指定类型
this 匹配代理对象实例的类型
target 匹配目标对象实例的类型
args 匹配方法参数
bean 匹配 bean 的 id 或名称
@within 匹配类型是否含有注解
@target 匹配目标对象实例的类型是否含有注解
@annotation 匹配方法是否含有注解
@args 匹配方法参数类型是否含有注解

标签:匹配,service,切点,类型,Pointcut,SpringAOP,注解,表达式
From: https://www.cnblogs.com/zhoading/p/18304907

相关文章

  • Java中的SpringAOP、代理模式、常用AspectJ注解详解
      这篇文章主要介绍了Java中的SpringAOP、代理模式、常用AspectJ注解详解,Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务,例如审计和事务管理进行内聚性的开发,需要的朋友可以参考下 +目录一、AOP简述回到主题,何为AOP?AOP即面向切面编......
  • SpringAOP-代理方式-Cglib动态代理
    文章目录cglib动态代理cglib是基于继承的方式实现的是继承目标类从而产生代理类springaop底层使用的就是cglib的动态代理packagecom.itheima.cjlibproxy;importnet.sf.cglib.proxy.Callback;importnet.sf.cglib.proxy.Enhancer;importnet.sf.cglib.proxy.......
  • @Pointcut 的常用方式:execution,within,this,target,args,@within,@target,@args,@annotation
    @Pointcut的常用方式先了解几个概念文中会涉及几个概念,先了解一下。target用来表示目标对象,即需要通过aop来增强的对象。proxy代理对象,target通过aop增强之后生成的代理对象。AspectJAspectJ是什么?AspectJ是一个面向切面的框架,是目前最好用,最方便的AOP框架,和spring中的......
  • SpringAOP增强-几种不同将注解和切面方法的关联方式
    @Around的作用既可以在目标方法之前织入增强动作,也可以在执行目标方法之后织入增强动作;可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止目标目标方法的执行;可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值;当需要改变目标方法的返回值时,只能使用Aro......
  • python根据达芬奇场景分析保存的edl文件,智能裁切输出4K视频画面(不带声音)-自动找到MP
    使用前先将mp4对应的EDL文件命名为相同的名字,如:春天.mp4,春天.edl只处理持续时间大于5帧的画面批量处理指定文件夹下所有文件,处理失败的直接跳过,接着继续处理其他的 importcv2importosimporttimeimportdatetimeimportshutilfrommoviepy.editorimportVideoFile......
  • python根据达芬奇场景分析保存的edl文件,智能裁切输出4K视频画面(不带声音)-自动找到MP
    使用前先将mp4对应的EDL文件命名为相同的名字,如:春天.mp4,春天.edl只处理持续时间大于5帧的画面importcv2importosimporttimeimportdatetimeimportshutilfrommoviepy.editorimportVideoFileClip#读取切分文件defreadQiFenWenJian(filename):withopen(......
  • 深入理解 SpringAOP(一):AOP 组件概述
    概述spring-aop模块是Spring框架中最重要的组件之一,它为我们提供了强大的AOP功能,并为其他扩展功能(如声明式事务、声明式异步处理等)提供了支持。在本文中,我们将深入探讨SpringAOP的源码,从代理对象的创建开始,揭示SpringAOP的运行机制。首先,在阅读这篇文章前,请先确保对Sp......
  • 深入理解 SpringAOP(二):AOP的执行流程
    概述在之前的文章中,我们已经对SpringAOP的关键组件进行了描述,并且了解了其基本操作和流程。在本文中,我们将进一步深入源码,揭示SpringAOP的内部实现细节,理解其运行机制的每个环节,包括切面的织入方式、代理对象的创建过程、连接点的定位与匹配等。通过对完整运行流程的深入研究......
  • Java-SpringAop 编程式事物实现
    SpringAop编程式事物实现1.数据库事物特性原子性多个数据库操作是不可分割的,只有所有的操作都执行成功,事物才能被提交;只要有一个操作执行失败,那么所有的操作都要回滚,数据库状态必须回复到操作之前的状态一致性事物操作成功后,数据库的状态和业务规则必须一致。例如:从A......
  • SpringAOP介绍与简单实现
    AOP简介AOP(AspectOrientedProgarmming)意为:面向切面编程,可以通过预编译的方式和运行期动态代理实现在不修改源代码的情况下给程序动态同一添加功能的一种技术。AOP的编程思想就是把很多类对象重的横切问题点,从业务逻辑中分离出来,从而达到解耦的目的,增加代码的重用性,提高开......