Spring AOP切点表达式(Pointcut)详解 |
您所在的位置:网站首页 › spring切点表达式注解 › Spring AOP切点表达式(Pointcut)详解 |
Spring 的 AOP 中的一个核心概念是切点(Pointcut),切点表达式定义通知(Advice)执行的范围。 理解 AOP 通知参阅: 《Spring AOP通知(Advice)详解》 一、概述Spring AOP 只支持 Spring Bean 的方法切入,所以切点表达式只会匹配 Bean 类中的方法。 二、切点表达式配置 1. 内置配置定义切面通知时,在 @Before 或 @AfterReturning 等通知注解中指定表达式。 @Aspect @Component public class DemoAspect { @Before("execution(* cn.codeartist.spring.aop.advice.*.*(..))") public void doBefore() { // 自定义逻辑 } } 2. 注解配置在切面类中,先定义一个方法并使用 @Pointcut 注解来指定表达式。 然后在定义切面通知时,在通知注解中指定定义表达式的方法签名。 @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 注解来指定表达式。 public class CommonPointcut { @Pointcut("execution(* cn.codeartist.aop.*..*(..))") public void pointcut() { // 注意定义切点的方法的访问权限为public } }在切面类中定义切面通知时,在通知注解中指定定义表达式的方法签名全路径。 @Aspect @Component public class DemoAspect { @Before("cn.codeartist.aop.CommonPointcut.pointcut()") public void commonPointcut() { // 自定义逻辑 } } 二、切点表达式类型Spring AOP 支持以下几种切点表达式类型。 execution匹配方法切入点。根据表达式描述匹配方法,是最通用的表达式类型,可以匹配方法、类、包。 表达式模式: execution(modifier? ret-type declaring-type?name-pattern(param-pattern) throws-pattern?)表达式解释: modifier:匹配修饰符,public, private 等,省略时匹配任意修饰符 ret-type:匹配返回类型,使用 * 匹配任意类型 declaring-type:匹配目标类,省略时匹配任意类型 .. 匹配包及其子包的所有类 name-pattern:匹配方法名称,使用 * 表示通配符 * 匹配任意方法 set* 匹配名称以 set 开头的方法 param-pattern:匹配参数类型和数量 () 匹配没有参数的方法 (..) 匹配有任意数量参数的方法 (*) 匹配有一个任意类型参数的方法 (*,String) 匹配有两个参数的方法,并且第一个为任意类型,第二个为 String 类型 throws-pattern:匹配抛出异常类型,省略时匹配任意类型 使用示例: // 匹配public方法 execution(public * *(..)) // 匹配名称以set开头的方法 execution(* set*(..)) // 匹配AccountService接口或类的方法 execution(* com.xyz.service.AccountService.*(..)) // 匹配service包及其子包的类或接口 execution(* com.xyz.service..*(..)) within匹配指定类型。匹配指定类的任意方法,不能匹配接口。 表达式模式: within(declaring-type)使用示例: // 匹配service包的类 within(com.xyz.service.*) // 匹配service包及其子包的类 within(com.xyz.service..*) // 匹配AccountServiceImpl类 within(com.xyz.service.AccountServiceImpl) this匹配代理对象实例的类型,匹配在运行时对象的类型。 注意:基于 JDK 动态代理实现的 AOP,this 不能匹配接口的实现类,因为代理类和实现类并不是同一种类型,详情参阅《Spring中的AOP和动态代理》 表达式模式: this(declaring-type)使用示例: // 匹配代理对象类型为service包下的类 this(com.xyz.service.*) // 匹配代理对象类型为service包及其子包下的类 this(com.xyz.service..*) // 匹配代理对象类型为AccountServiceImpl的类 this(com.xyz.service.AccountServiceImpl) target匹配目标对象实例的类型,匹配 AOP 被代理对象的类型。 表达式模式: target(declaring-type)使用示例: // 匹配目标对象类型为service包下的类 target(com.xyz.service.*) // 匹配目标对象类型为service包及其子包下的类 target(com.xyz.service..*) // 匹配目标对象类型为AccountServiceImpl的类 target(com.xyz.service.AccountServiceImpl)三种表达式匹配范围如下: 表达式匹配范围withinthistarget接口✘✔✔实现接口的类✔〇✔不实现接口的类✔✔✔表格可以左右滑动 args匹配方法参数类型和数量,参数类型可以为指定类型及其子类。 使用 execution 表达式匹配参数时,不能匹配参数类型为子类的方法。 表达式模式: args(param-pattern)使用示例: // 匹配参数只有一个且为Serializable类型(或实现Serializable接口的类) args(java.io.Serializable) // 匹配参数个数至少有一个且为第一个为Example类型(或实现Example接口的类) args(cn.codeartist.spring.aop.pointcut.Example,..) bean通过 bean 的 id 或名称匹配,支持 * 通配符。 表达式模式: bean(bean-name)使用示例: // 匹配名称以Service结尾的bean bean(*Service) // 匹配名称为demoServiceImpl的bean bean(demoServiceImpl) @within匹配指定类型是否含有注解。当定义类时使用了注解,该类的方法会被匹配,但在接口上使用注解不匹配。 使用示例: // 匹配使用了Demo注解的类 @within(cn.codeartist.spring.aop.pointcut.Demo) @target匹配目标对象实例的类型是否含有注解。当运行时对象实例的类型使用了注解,该类的方法会被匹配,在接口上使用注解不匹配。 使用示例: // 匹配对象实例使用了Demo注解的类 @target(cn.codeartist.spring.aop.pointcut.Demo) @annotation匹配方法是否含有注解。当方法上使用了注解,该方法会被匹配,在接口方法上使用注解不匹配。 使用示例: // 匹配使用了Demo注解的方法 @annotation(cn.codeartist.spring.aop.pointcut.Demo) @args匹配方法参数类型是否含有注解。当方法的参数类型上使用了注解,该方法会被匹配。 使用示例: // 匹配参数只有一个且参数类使用了Demo注解 @args(cn.codeartist.spring.aop.pointcut.Demo) // 匹配参数个数至少有一个且为第一个参数类使用了Demo注解 @args(cn.codeartist.spring.aop.pointcut.Demo,..)切点表达式的参数匹配 切点表达式中的参数类型,可以和通知方法的参数通过名称绑定,表达式中不需要写类或注解的全路径,而且能直接获取到切面拦截的参数或注解信息。 @Before("pointcut() && args(name,..)") public void doBefore(String name) { // 切点表达式增加参数匹配,可以获取到name的信息 } @Before("@annotation(demo)") public void doBefore(Demo demo) { // 这里可以直接获取到Demo注解的信息 }切点表达式的参数匹配同样适用于 @within, @target, @args 怎样编写一个好的切点表达式? 要使切点的匹配性能达到最佳,编写表达式时,应该尽可能缩小匹配范围,切点表达式分为三大类: 类型表达式:匹配某个特定切入点,如 execution 作用域表达式:匹配某组切入点,如 within 上下文表达式:基于上下文匹配某些切入点,如 this、target 和 @annotation 一个好的切点表达式应该至少包含前两种(类型和作用域)类型。 作用域表达式匹配的性能非常快,所以表达式中尽可能使用作用域类型。 上下文表达式可以基于切入点上下文匹配或在通知中绑定上下文。 单独使用类型表达式或上下文表达式比较消耗性能(时间或内存使用)。 三、切点表达式组合使用 &&、|| 和 ! 来组合多个切点表达式,表示多个表达式“与”、“或”和“非”的逻辑关系。 这可以用来组合多种类型的表达式,来提升匹配效率。 // 匹配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匹配方法参数类型是否含有注解表格可以左右滑动 3. 示例代码Gitee 仓库: https://gitee.com/code_artist/spring CodeArtist 码匠,编码的匠人,程序的艺术家。 98篇原创内容 公众号
|
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |