Spring AOP切点表达式使用及说明

 更新时间:2024年05月13日 09:15:22   作者:ZerahMu  
这篇文章主要介绍了Spring AOP切点表达式使用及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

切点表达式

在Spring AOP中,连接点始终代表方法的执行。切入点是与连接点匹配的谓词,切入点表达语言是以编程方式描述切入点的方式。

切点表达式是除过AOP逻辑之外我们开发主要关注的东西,本小结对各种表达式作以说明,spring aop中目前有9种切入点表达式的写法

  • execute
  • within
  • this
  • target
  • args
  • @target
  • @within
  • @annotation
  • @args

一、execute表达式

拦截任意公共方法

execution(public * *(..))

拦截以set开头的任意方法

execution(* set*(..))

拦截类或者接口中的方法

拦截AccountService(类、接口)中定义的所有方法
execution(* com.xyz.service.AccountService.*(..))

拦截包中定义的方法,不包含子包中的方法

拦截com.xyz.service包中所有类中任意方法,**不包含**子包中的类
execution(* com.xyz.service.*.*(..))

拦截包或者子包中定义的方法

拦截com.xyz.service包或者子包中定义的所有方法
execution(* com.xyz.service..*.*(..))

二、within表达式

表达式格式:包名.* 或者 包名…*

拦截包中任意方法,不包含子包中的方法

拦截service包中任意类的任意方法
within(com.xyz.service.*)

拦截包或者子包中定义的方法

拦截service包及子包中任意类的任意方法
within(com.xyz.service..*)

三、this表达式

代理对象为指定的类型会被拦截

目标对象使用aop之后生成的代理对象必须是指定的类型才会被拦截,注意是目标对象被代理之后生成的代理对象和指定的类型匹配才会被拦截
this(com.xyz.service.AccountService)

this表达式的使用,可能不是很好理解,借用示例说明一下:

package com.ms.aop.jthis.demo1;
​
public interface IService {
    void m1();
}

package com.ms.aop.jthis.demo1;
​
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
​
@Slf4j
@Component
public class ServiceImpl implements IService {
    @Override
    public void m1() {
        log.info("切入点this测试!");
    }
}

package com.ms.aop.jthis.demo1;
​
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
public class Interceptor1 {
​
    @Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")
    public void pointcut() {
    }
​
    @Around("pointcut()")
    public Object invoke(ProceedingJoinPoint invocation) throws Throwable {
        log.info("方法执行之前");
        Object result = invocation.proceed();
        log.info("方法执行完毕");
        return result;
    }
}

package com.ms.aop.jthis.demo1;
​
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
​
@ComponentScan(basePackageClasses = {Client.class})
@EnableAspectJAutoProxy
@Slf4j
public class Client {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Client.class);
        IService service = annotationConfigApplicationContext.getBean(IService.class);
        service.m1();
        log.info("{}", service instanceof ServiceImpl);
    }
}

执行结果

10:27:12.277 [main] INFO com.ms.aop.jthis.demo1.ServiceImpl - 切入点this测试!

10:27:12.277 [main] INFO com.ms.aop.jthis.demo1.Client - false

  • @EnableAspectJAutoProxy:表示若spring创建的对象如果实现了接口,默认使用jdk动态代理,如果没有实现接口,使用cglib创建代理对象 所以 service 是使用jdk动态代理生成的对象,service instanceof ServiceImpl 为 false
  • @Pointcut(“this(com.ms.aop.jthis.demo1.ServiceImpl)”) 表示被spring代理之后生成的对象必须为com.ms.aop.jthis.demo1.ServiceImpl才会被拦截,但是service不是ServiceImpl类型的对象了【这是因为默认采用的JDK动态代理,所以AOP生成的是代理对象,因此也service就不是ServiceImpl类型的对象】,所以不会被拦截

修改代码

@EnableAspectJAutoProxy(proxyTargetClass = true)
proxyTargetClass=true表示强制使用cglib来生成代理对象

执行结果:

10:34:50.755 [main] INFO com.ms.aop.jthis.demo1.ServiceImpl - 切入点this测试!

10:34:50.756 [main] INFO com.ms.aop.jthis.demo1.Interceptor1 - 方法执行完毕

10:34:50.756 [main] INFO com.ms.aop.jthis.demo1.Client - true

service 为 ServiceImpl类型的对象,所以会被拦截,因为熟悉CGLIB理论知识的同学都知道,CGLIB生成的代理对象是源类型的子类,因此service肯定是ServiceImpl类型的对象了,因为多态属于关系。 

四、target表达式

目标对象为指定的类型被拦截

target(com.xyz.service.AccountService)
目标对象为AccountService类型的会被代理

this 和 target 的不同点

  • this作用于代理对象,target作用于目标对象
  • this表示目标对象被代理之后生成的代理对象和指定的类型匹配会被拦截,匹配的是代理对象
  • target表示目标对象和指定的类型匹配会被拦截,匹配的是目标对象

五、args 表达式

匹配方法中的参数

匹配只有一个参数,且类型为
com.ms.aop.args.demo1.UserModel@Pointcut("args(com.ms.aop.args.demo1.UserModel)")
- 匹配多个参数
args(type1,type2,typeN)

匹配任意多个参数

匹配第一个参数类型为com.ms.aop.args.demo1.UserModel的所有方法, .. 表示任意个参数
@Pointcut("args(com.ms.aop.args.demo1.UserModel,..)")

六、@target表达式

匹配的目标对象的类有一个指定的注解

目标对象中包含com.ms.aop.jtarget.Annotation1注解,调用该目标对象的任意方法都会被拦截
@target(com.ms.aop.jtarget.Annotation1)

七、@within表达式

指定匹配必须包含某个注解的类里的所有连接点

声明有com.ms.aop.jwithin.Annotation1注解的类中的所有方法都会被拦截
​​​​​​​@within(com.ms.aop.jwithin.Annotation1)

@target 和 @within 的不同点

  • @target(注解A):判断被调用的目标对象中是否声明了注解A,如果有,会被拦截
  • @within(注解A): 判断被调用的方法所属的类中是否声明了注解A,如果有,会被拦截
  • @target关注的是被调用的对象,@within关注的是调用的方法所在的类

八、@annotation表达式

匹配有指定注解的方法(注解作用在方法上面)

@annotation(com.ms.aop.jannotation.demo2.Annotation1)

被调用的方法包含指定的注解

九、@args表达式

方法参数所属的类型上有指定的注解,被匹配

注意:是方法参数所属的类型上有指定的注解,不是方法参数中有注解

匹配1个参数,且第1个参数所属的类中有Anno1注解

  • @args(com.ms.aop.jargs.demo1.Anno1)
  • 匹配多个参数,且多个参数所属的类型上都有指定的注解
  • @args(com.ms.aop.jargs.demo1.Anno1,com.ms.aop.jargs.demo1.Anno2)
  • 匹配多个参数,且第一个参数所属的类中有Anno1注解
  • @args(com.ms.aop.jargs.demo2.Anno1,…)

切点表达式组合

另外,可以使用&&、||、!、三种运算符来组合切点表达式,表示与或非的关系。

@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods() {}

@Pointcut("execution(* *..create*(Long,..))")
public void firstLongParamMethods() {}

@Pointcut("repositoryMethods() && firstLongParamMethods()")
public void entityCreationMethods() {}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java导出Excel通用工具类实例代码

    Java导出Excel通用工具类实例代码

    这篇文章主要给大家介绍了关于Java导出Excel通用工具类的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • SpringBoot集成七牛云OSS的示例详解

    SpringBoot集成七牛云OSS的示例详解

    OSS的英文全称是Object Storage Service,翻译成中文就是对象存储服务,官方一点解释就是对象存储是一种使用HTTP API存储和检索非结构化数据和元数据对象的工具,本文给大家详细介绍了SpringBoot集成七牛云OSS的示例,需要的朋友可以参考下
    2023-11-11
  • Java多线程下载文件实例详解

    Java多线程下载文件实例详解

    这篇文章主要为大家详细介绍了Java多线程下载文件的实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • 解决mybatis三表连接查询数据重复的问题

    解决mybatis三表连接查询数据重复的问题

    这篇文章主要介绍了解决mybatis三表连接查询数据重复的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • SpringCloud中的分布式锁用法示例详解(Java+Redis SETNX命令)

    SpringCloud中的分布式锁用法示例详解(Java+Redis SETNX命令)

    在Spring Cloud项目中,使用Java和Redis结合实现的分布式锁可以确保订单的一致性和并发控制,分布式锁的使用能够在多个实例同时提交订单时,仅有一个实例可以成功进行操作,本文给大家介绍Spring,Cloud中的分布式锁用法详解(Java+Redis SETNX命令),感兴趣的朋友一起看看吧
    2023-10-10
  • MyBatis源码分析之日志记录详解

    MyBatis源码分析之日志记录详解

    这篇文章主要给大家介绍了关于MyBatis源码分析之日志记录的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用MyBatis具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-11-11
  • Java实现将一段文字按照句号和感叹号进行分割的示例代码

    Java实现将一段文字按照句号和感叹号进行分割的示例代码

    这篇文章介绍了一个用Java实现的代码示例,该代码能够将一段文字按照句号和感叹号进行分割,并在分割后去除每段的前后空格,使用了正向后行断言和StringBuilder来提高效率,需要的朋友可以参考下
    2026-01-01
  • java ArrayBlockingQueue阻塞队列的实现示例

    java ArrayBlockingQueue阻塞队列的实现示例

    ArrayBlockingQueue是一个基于数组实现的阻塞队列,本文就来介绍一下java ArrayBlockingQueue阻塞队列的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • maven项目打包如何去掉不需要的module

    maven项目打包如何去掉不需要的module

    文章总结:在my-project工程依赖my-core和my-common,且my-project在总工程AAA中时,建议通过以下两种方案优化打包流程:1. 使用pom区分,重新编写pom文件,并指定需要重新编译的工程到modules中,然后在编译时指定pom文件;
    2024-12-12
  • 如何更优雅的关闭java文本、网络等资源

    如何更优雅的关闭java文本、网络等资源

    这篇文章主要介绍了如何更优雅的关闭java文本、网络等资源,在 finally 的关闭代码中,还要再来一个 try/catch,看着是不是很难受,很不优雅,很想干掉这个 finally!,需要的朋友可以参考下
    2019-06-06

最新评论