Spring AOP切点表达式(Pointcut)详解

简介: Spring 的 AOP 中的一个核心概念是切点(Pointcut),切点表达式定义通知(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


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

表达式模式:

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)

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

表达式匹配范围 within this target
接口
实现接口的类
不实现接口的类


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
  • 上下文表达式:基于上下文匹配某些切入点,如 thistarget@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

目录
相关文章
|
29天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
12天前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
40 5
|
17天前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
47 8
|
17天前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
17天前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
32 5
|
17天前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
27 4
|
2月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
43 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
1月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
30 1
|
1月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
35 0
|
3月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP