往期相关文章:
AOP核心概念和SpringAOP切面
10分钟入门SpringAOP

文章目录

  • 导言
    • 什么是PCD
    • PCD一览图
  • 使用指南
    • execution
    • within
    • this
    • target
    • args
      • 和带参数匹配`execution`区别
    • @target
    • @args
    • @within
    • @annotation
    • bean
  • 其他
    • 组合使用
    • 命名绑定模式
    • argNames
  • 参考文章

导言

什么是PCD

PCD(pointcut designators )就是SpringAOP的切点表达式。SpringAOP的PCD是完全兼容AspectJ的,一共有10种。

PCD一览图

使用指南

SpringAOP是基于动态代理实现的,以下以目标对象表示被代理bean,代理对象表示AOP构建出来的bean。目标方法表示被代理的方法。

execution

execution是最常用的PCD。它的匹配式模板如下展示:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
execution(修饰符匹配式? 返回类型匹配式 类名匹配式? 方法名匹配式(参数匹配式) 异常匹配式?)

代码块中带?符号的匹配式都是可选的,对于execution PCD必不可少的只有三个:

  1. 返回值匹配值
  2. 方法名匹配式
  3. 参数匹配式

举例分析: execution(public * ServiceDemo.*(..)) 匹配public修饰符,返回值是*,即任意返回值类型都行,ServiceDemo是类名匹配式不一定要全路径,只要全局依可见性唯一就行.*是方法名匹配式,匹配所有方法,..是参数匹配式,匹配任意数量、任意类型参数的方法。

再举一些其他例子:

  • execution(* com.xyz.service..*.*(..)): 匹配com.xyz.service及其子包下的任意方法。

  • execution(* joke(Object+))):匹配任意名字为joke的方法,且其动态入参是是Object类型或该类的子类。

  • execution(* joke(String,..)):匹配任意名字为joke的方法,该方法 一个入参为String(不可以为子类),后面可以有任意个入参且入参类型不限

  • execution(* com..*.*Dao.find*(..)): 匹配指定包下find开头的方法

  • execution(* com.baobaotao.Waiter+.*(..)) : 匹配com.baobaotao包下Waiter及其子类的所有方法。

within

筛选出某包下的所有类,注意要带有*

  • within(com.xyz.service.*)com.xyz.service包下的类,不包括子包

  • within(com.xyz.service..*)com.xyz.service包下及其子包下的类

this

常用于命名绑定模式。对由代理对象的类型进行过滤筛选。

如果目标类是基于接口实现的,则this()中可以填该接口的全路径名,否则非接口实现由于是基于CGLIB实现的,this中可以填写目标类的全路径名。

this(com.xyz.service.AccountService): 代理类是com.xyz.service.AccountService或其子类。

使用@EnableAspectJAutoProxy(proxyTargetClass = true)可以强制使用CGLIB。否则默认首先使用jdk动态代理,jdk代理不了才会用CGLIB。

target

this作用于代理对象,target作用于目标对象。

target(com.xyz.service.AccountService): 被代理类(目标对象)是com.xyz.service.AccountService或其子类

args

常用于对目标方法的参数匹配。一般不单独使用,而是配合其他PCD来使用。args可以使用命名绑定模式,如下举例:

@Aspect // 切面声明
@Component // 注入IOC
@Slf4j
class AspectDemo {@Around("within(per.aop.*) && args(str)") // 在per.aop包下,且被代理方法的只有一个参数,参数类型是String或者其子类@SneakyThrowspublic Object logAspect(ProceedingJoinPoint pjp, String str) { String signature = pjp.getSignature().toString();log.info("{} start,param={}", signature, pjp.getArgs());Object res = pjp.proceed();log.info("{} end", signature);return res;}
}
  1. 如果args中是参数名,则配合切面(advice)方法的使用来确定要匹配的方法参数类型。
  2. 如果args中是类型,例如@Around("within(per.aop.*) && args(String)”),则可以不必使用切面方法来确定类型,但此时也不能使用参数绑定了见下文了。

虽然args()支持+符号,但本省args()就支持子类通配。

和带参数匹配execution区别

举个例子: args(com.xgj.Waiter)等价于 execution(* *(com.xgj.Waiter+))。而且execution不能支持带参数的advice。

@target

使用场景举例: 当一个Service有多个子类时, 某些子类需要打日志,某些子类不需要打日志时可以如下处理(配合java多态):

筛选出具有给定注解的被代理对象是对象不是类,@target是动态的。如下自定义一个注解LogAble:

//全限定名: annotation.LogAble
@Target({ElementType.TYPE,ElementType.PARAMETER}) // 支持在方法参数、类上注
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAble {}

假如需要“注上了这个注解的所有类的的public方法“都打日志的话日志逻辑要自定义,可以如下这么写PCD,当然对应方法的bean要注入到SpringIOC容器中:

@Around("@target(annotation.LogAble) && execution(public * *.*(..))")
// 自定义日志逻辑

@args

对于目标方法参数的运行时类型要有@args指定的注解。是方法参数的类型上有指定注解,不是方法参数上带注解。

使用场景: 假如参数类型有多个子类,只有某个子类才可以匹配该PCD。

  • @args(com.ms.aop.jargs.demo1.Anno1): 匹配1个参数,且第1个参数运行时需要有Anno1注解

  • @args(com.ms.aop.jargs.demo1.Anno1,..)匹配一个或多个参数,第一个参数运行时需要带上Anno1注解。

  • @args(com.ms.aop.jargs.demo1.Anno1,com.ms.aop.jargs.demo1.Anno2): 一参匹配Anno1,二参匹配Annno2 。

@within

运行时类型的@target。@target关注的是被调用的对象,@within关注的是调用的方法所在的类。

@target 和 @within 的不同点:

@target(注解A):判断被调用的目标对象中是否声明了注解A,如果有,会被拦截

@within(注解A): 判断被调用的方法所属的中是否声明了注解A,如果有,会被拦截

@annotation

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

bean

根据beanNam来匹配。支持*通配符。

bean(*Service) // 匹配所有Service结尾的Service

其他

组合使用

PCD之间支持,&& || !三种运算符。上文示例中就使用了&& 运算符。||表示或(不是短路或)。!表示非。

命名绑定模式

上文中的@Around("within(per.aop.*) && args(str)")示例就是使用了命名绑定模式,在PCD中写上变量名,在方法上对变量名的类型进行限定。

@Around("within(per.aop.*) && args(str)")
public Object logAspect(ProceedingJoinPoint pjp, String str) { ...}

如上举例,str要是String类型或其子类,且方法入参只能有一个。

name binding only allowed in target, this, and args pcds

命名绑定模式只支持target、this、args三种PCD。

argNames

观察源码可以发现,所有的Advice注解都带有argNames字段,例如@Around:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Around {String value();String argNames() default "";
}

什么情况下会使用这个属性呢,如下举例解释:

@Around(value = "execution(* TestBean.paramArgs(..))  && args(decimal,str,..)&& target(bean)", argNames = "pjp,str,decimal,bean")
@SneakyThrows // proceed会抛受检异常
Object aroundArgs(ProceedingJoinPoint pjp,/*使用命名绑定模式*/ String str, BigDecimal decimal, Object bean) {// 在方法执行前做一些操作return  pjp.proceed();
}

argnames 必须要和args、target、this标签一起使用。虽然实际操作中可以不带,但官方建议所有带参数的都带,原因如下:

因此如果‘ argernames’属性没有指定,那么 Spring AOP 将查看类的调试信息,并尝试从局部变量表中确定参数名。只要使用调试信息(至少是‘-g: vars’)编译了类,就会出现此信息。使用这个标志编译的结果是:

(1)你的代码将会更容易被反向工程)

(2)类文件大小将会非常大(通常是无关紧要的)

(3)删除未使用的局部变量的优化将不会被编译器应用。

此外,如果编译的代码没有必要的调试信息,那么 Spring AOP 将尝试推断绑定变量与参数的配对。如果变量的绑定在可用信息下是不明确的,那么一个 AmbiguousBindingException 就会被抛出。如果上面的策略都失败了,那么就会抛出一个 IllegalArgumentException。

建议所有的advice注解里都带argNames,反正idea也会提醒。

参考文章

  1. Spring文档
  2. SpringAOP Point表达式

我用一张图彻底了解 SpringAOP 切面表达式相关推荐

  1. 不带头节点的链表有哪些缺点_23张图!万字详解「链表」,从小白到大佬!

    链表和数组是数据类型中两个重要又常用的基础数据类型. 数组是连续存储在内存中的数据结构,因此它的优势是可以通过下标迅速的找到元素的位置,而它的缺点则是在插入和删除元素时会导致大量元素的被迫移动,为了解 ...

  2. 3dmax图像采样器抗锯齿_内幕揭秘!同样的场景同一张图,用3DMAX网渲平台进行二次渲染时间竟然相差3个小时之多!...

    一个分辨率:4000*2000的室内客餐厅,3dmax版本是2014版本,渲染器版本为vray3.63,机器:阿里云1台服务器,这个同样的场景同样的参数同一张图,用3dmax网渲平台进行二次渲染发现时 ...

  3. 17张图揭密支付宝系统架构

    支付宝的系统架构图,仅供参考.不管是不是支付行业,都值得我们参考,学习. image image image image image image image image image image ima ...

  4. 参加海峡两岸城市地理信息系统论坛2010 年会(一张图、规划信息化和空间句法的碎碎念)...

    上周末去清华建筑学院开了个会,叫做海峡两岸城市地理信息系统论坛2010 年会,主题很大,但是内容比较集中一些,就是围绕着GIS与城市规划.一天下来听了20个报告,挺佩服主办方的时间控制,这么密集的报告 ...

  5. 7000 字 23 张图,Pandas一键生成炫酷的动态交互式图表

    作者 | 俊欣 来源 | 关于数据分析与可视化 今天小编来演示一下如何用pandas一行代码来绘制可以动态交互的图表,并且将绘制的图表组合到一起,组成可视化大屏,本次小编将要绘制的图表有 折线图 散点 ...

  6. 手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

    作者 | 写代码的明哥 来源 | Python编程时光 这篇文章本应该是属于 HTTP 里的一部分内容,但是我看内容也挺多的,就单独划分一篇文章来讲下. 什么是跨域请求 要明白什么叫跨域请求,首先得知 ...

  7. 有答案了!一张图告诉你到底学Python还是Java!你咋看?

    2019年,该学Java还是Python? 不,实际上应该这样问:都9102年了,难道有谁不想成为Python程序员吗? 作为"常青树大佬"Java 和"新晋大佬&quo ...

  8. 一张图看懂微软人工智能的布局

    一向低调的微软,最近在人工智能领域前所未有地高调了起来. 前两天,微软(亚洲)互联网工程院发布了一份技术声明,称人类历史上第一次与人工智能进行全双工语音电话,并不是发生在美国,而是在中国!这个人工智能 ...

  9. 学Java还是Python?一张图告诉你!

    Java 和 Python 一直都是两种很火很强大的编程语言,对于刚开始起步学习编程的同学来说,会迷惑且最经常问的问题是,我该学 Java 还是 Python,是不是 Python 容易学,或是应该先 ...

  10. 我以前一直没有真正理解支持向量机,直到我画了一张图!

    选自towardsdatascience 作者:Rohit Pandey 编译:机器之心(almosthuman2014) 点击文末阅读原文 我以前一直没有真正理解支持向量机,直到我画了一张图. 1. ...

最新文章

  1. 【NOIP2011 Day 2】观光公交
  2. github和dockerhub制作k8s镜像
  3. SQLite中利用事务处理优化DB操作
  4. SHA-3的获胜者:keccak - 在 3GPP TS 35.231、FIPS 202 和 SP 800-185 中标准化
  5. Ajax实例一:利用服务器计算
  6. 拦截JQuery的ajax
  7. 页面滚动可视区域的获取
  8. POJ3068 Shortest pair of paths 【费用流】
  9. 075 json和pickle模块
  10. Web前端开发工程师需要掌握哪些核心技能?
  11. 山西阳泉中考计算机科目,阳泉中考信息技术考试
  12. 天气预报:强势力的“.fans+体育”旋风正席卷全球!
  13. 逆向工程的几种应用方向
  14. java常见的网络异常
  15. 微信小程序云调用security.mediaCheckAsync接口成功实例(内容安全审核接口)
  16. 【学生管理系统】用户登录三种验证方式—图片验证、短信验证、邮件验证
  17. el-tree 默认展开第一级节点
  18. 广东第二师范学院计算机科学与技术(软件工程)的专业在哪,广东第二师范学院好就业吗?广东第二师范学院就业如何?...
  19. 基金持仓数据分析,满仓干还是等风来?
  20. AD使用技巧——如何向AD里面导入图片(PCB打印图片、二维码)教程适用各个版本(17版及以前、18及以后、19、20、21版)(内附脚本文件下载)

热门文章

  1. 【力扣面试】面试题 04.02. 最小高度树(就是创建二叉平衡树)
  2. 【自定义WPS插件xlam】
  3. win10右键一直转圈_win10投屏不能使用的解决办法
  4. Java基础篇——垃圾回收
  5. 输入输出工具技术(ITTO)要背吗?——软考高项笔记8
  6. PMP-PMBOK(第六版)--49个过程ITTO汇总
  7. 惠普服务器DL380 Gen10/Gen9宕机重启
  8. Linux下的软硬链接介绍
  9. Pyltp的安装使用笔记
  10. 程序员考证书,有用吗?