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版简单云相册

    自己动手写一个java版简单云相册

    这篇文章主要为大家分享了自己动手写的一个java版简单云相册,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • Java 单向队列及环形队列的实现原理

    Java 单向队列及环形队列的实现原理

    本文主要介绍了Java 单向队列及环形队列的实现原理,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • Java中PriorityQueue实现最小堆和最大堆的用法

    Java中PriorityQueue实现最小堆和最大堆的用法

    很多时候都会遇到PriorityQueue,本文主要介绍了Java中PriorityQueue实现最小堆和最大堆的用法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • 在Spring 中使用@Aspect 控制自定义注解的操作

    在Spring 中使用@Aspect 控制自定义注解的操作

    这篇文章主要介绍了在Spring 中使用@Aspect 控制自定义注解的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 解决IDEA插件市场Plugins无法加载的问题

    解决IDEA插件市场Plugins无法加载的问题

    这篇文章主要介绍了解决IDEA插件市场Plugins无法加载的问题,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Java实现两人五子棋游戏(五) 判断是否有一方胜出

    Java实现两人五子棋游戏(五) 判断是否有一方胜出

    这篇文章主要为大家详细介绍了Java实现两人五子棋游戏,判断是否有一方胜出,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • 浅析java volatitle 多线程问题

    浅析java volatitle 多线程问题

    Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存
    2013-08-08
  • Java Web监听器Listener接口原理及用法实例

    Java Web监听器Listener接口原理及用法实例

    这篇文章主要介绍了Java Web监听器Listener接口原理及用法实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • SpringBoot整合atomikos实现跨库事务的详细方案

    SpringBoot整合atomikos实现跨库事务的详细方案

    这篇文章主要介绍了SpringBoot整合atomikos实现跨库事务,业务主要涉及政府及企业且并发量不大,所以采用XA事务,虽然性能有所损失,但是可以保证数据的强一致性,需要的朋友可以参考下
    2022-06-06
  • 记一次在idea离线使用maven问题(推荐)

    记一次在idea离线使用maven问题(推荐)

    这篇文章主要介绍了记一次在idea离线使用maven问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11

最新评论