zoukankan      html  css  js  c++  java
  • spring aop的@Before,@Around,@After,@AfterReturn,@AfterThrowing的理解

    aop的这几个注解的使用非常常见,但是他们的执行顺序,以及作为我们进入核心代码前的校验,是如何在校验失败不然他进入核心方法的?博客上确实有不少讲解的很详细,我在结尾也会推荐几篇。这里就几个重要的点和不明的点做下说明,前事不忘后事之师!

    1.AOP的基本概念

    切面(Aspect) :通知(advice)和切入点(pointcut)共同组成了切面(aspect),时间、地点和要发生的“故事”。可以从注解方式来理解,代码如下。 
    @aspect为类上面的注解——切面 
    @pointcut(…)——切入点。为此类内一个空方法上面的注解。可以把拦截的地址表达式表示为方法签名,利于使用起来方便。 
    @before@after等——通知。为此类下面的方法上面的注解。 
    三者在一块组成一个切面。

    @Aspect
    public class ExampleAspect {
    
      @Pointcut("execution(* com.psjay.example.spring.aop.*.*(..))")
      public void aPointcut() {
      }
    
      @Before("aPointcut()")
      public void beforeAdvice() {
          System.out.println("before advice is executed!");
      }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12



    连接点(Joinpoint) :程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。——可以理解为被aop拦截的类或者方法就是连接点。

    通知(Advice) :通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。——可以理解为被注解有@Before等advice注解的安全校验的方法,拦截了过来的请求要做什么逻辑的校验。

    切入点(Pointcut) :通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称。——可以理解为切面切向哪里?是个类或者某层的包路径。 
    目标对象(Target Object) :即被通知的对象。 
    AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理;反之,采用CGLIB代理。 
    织入(Weaving)把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机: 
      (1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才能做到,例如AspectJ的织入编译器; 
      (2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码; 
      (3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理是使用了JDK的动态代理。

    2 通知(Advice)类型的说明

    @Before 前置通知(Before advice) :在某连接点(JoinPoint)——核心代码(类或者方法)之前执行的通知,但这个通知不能阻止连接点前的执行。为啥不能阻止线程进入核心代码呢?因为@Before注解的方法入参不能传ProceedingJoinPoint,而只能传入JoinPoint。要知道从aop走到核心代码就是通过调用ProceedingJionPoint的proceed()方法。而JoinPoint没有这个方法。 
    这里牵扯区别这两个类:Proceedingjoinpoint 继承了 JoinPoint 。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。暴露出这个方法,就能支持 aop:around 这种切面(而其他的几种切面只需要用到JoinPoint,这跟切面类型有关), 能决定是否走代理链还是走自己拦截的其他逻辑。建议看一下 JdkDynamicAopProxy的invoke方法,了解一下代理链的执行原理。这样你就能明白 proceed方法的重要性。

    @After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

    @AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。

    @Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。这时aop的最重要的,最常用的注解。用这个注解的方法入参传的是ProceedingJionPoint pjp,可以决定当前线程能否进入核心方法中——通过调用pjp.proceed();

    @AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。

    3 advice(通知)注解的执行先后顺序

    这里说下简单情况——针对一个方法只被一个aspect类拦截时,aspect类内部的 advice 将按照以下的顺序进行执行情况如下: 
    这里写图片描述

    这里写图片描述 
    解释:执行到核心业务方法或者类时,会先执行AOP。在aop的逻辑内,先走@Around注解的方法。然后是@Before注解的方法,然后这两个都通过了,走核心代码,核心代码走完,无论核心有没有返回值,都会走@After方法。然后如果程序无异常,正常返回就走@AfterReturn,有异常就走@AfterThrowing。

    复杂的同一个方法被多个Aspect类拦截请参看博文:Spring AOP @Before @Around @After 等 advice 的执行顺序

    4 在aop中校验不通过如何不让程序进入核心代码?

    通过aop中注解的执行的先后顺序我们知道,校验发生在核心代码前面的只剩下两个——@Before,@Around。 
    @Before : 这个注解只有在异常时才不会走核心方法——连接点。正常@Before无法阻止当前线程进入连接点。 
    @Around : 这个注解在连接点前后执行。并且注解的方法传入的ProceedingJionPoint 类中封装的代理方法proceed()可以让当前线程从aop方法转到连接点——核心代码方法。所以一般我们用这个注解,如果aop的安全校验不通过,则不调用proceed()方法,就永远不会进入连接点。 
    除此外,要注意除了Around注解的方法可以传ProceedingJionPoint 外,别的几个都不能传这个类。但是普通的数据类型是不限制的。注解的方法的返回值也不限制,可以自由限制。

    参考博文: 
    1.小曹学spring–基于@AspectJ和Schema的AOP 
    2.彻底征服 Spring AOP 之 理论篇 
    3.利用Spring AOP自定义注解解决日志和签名校验 
    4.Spring AOP @Before @Around @After 等 advice 的执行顺序

  • 相关阅读:
    CentOS 安装Python3, pip3
    Pyinstaller打包python程序,以及遇到的问题:Cannot find existing PyQt5 plugin directories
    [Python] fetchone()和fetchall()
    在Linux命令行下,如何登录mysql server
    管理MySQL的客户端软件-MySQL Workbench
    在win10修改jupyter notebook(Anaconda安装)工作路径
    安装spark过程中出现Exception in thread "main" java.lang.UnsupportedClassVersionError错误的解决办法
    如何在win10本地主机操作系统和virtualBox 的Ubuntu之间设置共享文件夹
    支持向量机(SVM)
    特征工程(python)
  • 原文地址:https://www.cnblogs.com/suizhikuo/p/13941194.html
Copyright © 2011-2022 走看看