[09] 环绕通知和切入表达式

1、前置/后置/返回/异常/通知

Spring在执行AOP时实际上流程如下:
  • 首先执行前置通知
  • 然后执行目标组件,如果过程中出现异常,则执行异常通知
  • 然后执行后置通知
  • 最后判断如果目标组件正常执行,则再执行返回通知


  • before,前置通知,组件参数有JoinPoint
  • after,后置通知,组件参数有JoinPoint
  • after-returning,返回通知,组件参数除了JoinPoint,还有Object作为返回值,需在配置文件中定义
  • after-throwing,异常通知,组件参数除了JoinPoint,还有Throwable,会在目标程序抛出异常之后获取,也需要在配置文件中定义

2、环绕通知

通过环绕通知,可以实现前置通知、后置通知等等可以实现的功能。在类型为环绕通知的切面程序函数中,参数则不再是JoinPoint,而是ProceddingJoinPoint,它是JoinPoint的子类,进行了扩展,提供了proceed()函数,该函数的作用是调用目标组件,并返回目标组件返回的值。
public void doAround(ProceedingJoinPoint point) { 
    System.out.println("目标组件运行的前置通知");
    try {
        Object obj = point.proceed();
        System.out.println("目标组件的返回通知");
    } catch (Throwable throwable) {
        System.out.println("执行异常处理程序");
    }
    System.out.println("最终执行程序");
}
<aop:aspect ref="section">
    <!-- 通知为环绕,method为方法,pointcut-ref作用在哪些切入点 -->
    <aop:around method="doAround" pointcut-ref="targetPointCut"/>
</aop:aspect>

3、切入表达式

切入表达式用于声明Spring容器中哪些组件的函数是目标函数,也就是切面程序要作用到哪些组件的哪些函数上。

常用的切入表达式分为:
  • 按类匹配
    • 匹配的Java类中全部函数作为目标函数,使用within关键字
  • 按函数匹配
    • 匹配的函数作为目标函数,使用execution关键字
  • 按bean的id匹配
    • 匹配的bean中全部函数作为目标函数,使用bean关键字

3.1 按类匹配

匹配到指定类 .Xxx
<aop:pointcut id="targetPoint" expression="within(dulk.learn.aop.Target)" />

匹配到包下的类 .*
<aop:pointcut id="targetPoint" expression="within(dulk.learn.aop.*)" />

匹配到包下及子包下的类 ..*
<aop:pointcut id="targetPoint" expression="with(dulk..*)" />

3.2 按函数匹配

表达式的完整写法(以之前的demo为示例):
execution(String dulk.learn.aop.Target.print(String))
如上:
  • 首个String - 表示返回类型
  • dulk.learn.aop - 表示类的路径
  • Target - 表示类名
  • print - 表示函数名
  • 最后个String - 表示参数类型,用","分开


任意返回类型
execution(* dulk.learn.aop.Target.print(String))

任意返回类型下指定包下任意类
execution(* dulk.learn.aop.*.print(String))

任意返回类型下指定包下任意类任意函数
execution(* dulk.learn.aop.*.*(String))

任意返回类型下指定包或子包下任意类任意函数任意参数
execution(* dulk..*.*(..))


3.3 按bean的id匹配

表达式的关键字为bean,之后括号中的内容则为对应bean组件的id。

根据bean组件名称匹配:
<aop:pointcut id="targetPoint" expression="bean(target)" />

根据bean组件名称(含通配符)匹配,如有target1,target2等bean组件,则可以统一使用target*表示:
<aop:pointcut id="targetPoint" expression="bean(target*)" />

原文地址:https://www.cnblogs.com/deng-cc/p/9224369.html