首页 > 其他分享 >第15章-Spring AOP切点表达式(Pointcut)详解

第15章-Spring AOP切点表达式(Pointcut)详解

时间:2022-11-27 16:59:48浏览次数:72  
标签:15 service 匹配 Spring 切点 类型 注解 表达式

目录

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)

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

表达式匹配范围 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

标签:15,service,匹配,Spring,切点,类型,注解,表达式
From: https://www.cnblogs.com/code-artist/p/spring-15.html

相关文章

  • 第16章-Spring AOP中的基础API
    目录一、概述二、切点(Pointcut)三、通知(Advice)1.环绕通知2.前置通知3.异常通知4.后置通知四、通知者(Advisor)五、附录1.常用接口2.示例代码前面我们讲了基于XML和注......
  • 什么是SpringBoot
           ......
  • listener不能交给spring进行管理,需要自己new,不能注入其他对象,不能实现数据库操作
    ​​mybatis​​原生QueryWrapper<EduSubject>wrapperTwo=newQueryWrapper();wrapperTwo.ne("parent_id","0");.....业务和技术有区别的,业务是需要什么条件,输出什么结......
  • 第7章-Spring的Bean生命周期和扩展点
    目录一、生命周期二、Bean的扩展1.专用扩展点2.通用扩展点3.生命周期扩展点示例3.1实例化3.2属性填充3.2初始化3.4销毁4.生命周期扩展点顺序三、附录1.配置属性2......
  • 第4章-Spring基于Java配置的容器
    目录一、Bean管理1.元数据2.Full模式和Lite模式3.组合配置4.扫描类路径配置二、依赖管理1.依赖注入1.1参数注入1.2方法注入2.依赖关系3.懒加载三、附录1.常......
  • 第5章-Spring三种配置方式的混合和迁移
    目录一、配置兼容1.优先XML配置2.优先注解配置二、迁移方案1.XML配置至注解配置2.XML配置至Java配置三、附录1.配置属性2.常用注解3.示例代码Spring容器的......
  • 第6章-Spring同类型多个Bean的注入
    目录一、类型注入冲突二、解决冲突1.注入主要的2.注入指定的三、注入多个Bean1.注入集合2.注入Map3.Bean的顺序四、附录1.常用注解2.示例代码Spring容器中的B......
  • 第3章-Spring基于注解配置的容器
    目录一、Bean管理1.扫描类路径配置2.使用注解管理Bean二、依赖管理1.依赖注入1.1字段注入1.2构造器注入1.3Setter方法注入2.依赖关系3.懒加载三、附录1.配置属......
  • 第2章-Spring基于XML配置的容器
    目录一、Bean管理1.元数据2.Bean实例化2.1构造器实例化2.2静态工厂方式实例化2.3实例工厂方式实例化3.Bean作用域二、依赖注入1.依赖注入1.1构造器注入1.2Sett......
  • Spring mvc整合hibernate例子
    企业级项目实战(带源码)地址:[url]http://zz563143188.iteye.com/blog/1825168[/url]收集五年的开发资料及源码下载地址:[url]http://pan.baidu.com/......