(III)AOP:第七节:环绕通知

一、环绕通知

        (1)环绕通知是所有通知类型中功能最为强大的,能够全面地控制连接点,甚至可以控制是否执行连接点;
        (2)对于环绕通知来说,连接点的参数类型必须是 ProceedingJoinPoint。它是 JoinPoint 的子接口,允许控制何时执行,是否执行连接点;
        (3)在环绕通知中需要明确调用 ProceedingJoinPoint 的 proceed() 方法来执行被代理的方法。如果忘记这样做就会导致通知被执行了,但目标方法没有被执行;
        (4)注意:环绕通知的方法需要返回目标方法执行之后的结果,即调用 joinPoint.proceed() 的返回值,否则会出现空指针异常;
 
   环绕通知:
    /**
     * @Around:环绕:是Spring 中强大的通知,本质就是动态代理
     * 
     * try{
     *      //前置通知
     *      method.invoke(obj,args);
     *      //返回通知
     * }catch(e){
     *      //异常通知
     * }finally{
     *     //后置通知
     * }
     *
     * 四合一通知就是环绕通知
     * 环绕通知中有一个参数:ProceedingJoinPoint pjp
     */
    @Around("myPoint()")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {

        String methodName = pjp.getSignature().getName();
        Object[] args = pjp.getArgs();
        Object proceed = null;
        try {
            //@Before
            System.out.println("【环绕前置通知】---"+ methodName +"---【方法开始】");
            //就是利用反射调用目标方法即可,就是 method.invoke(obj, args)
            proceed = pjp.proceed(args);
            //@AfterReturning
            System.out.println("【环绕返回通知】---"+ methodName +"---【方法返回,返回值 "+ proceed +"】");
        } catch (Exception e) {
            //@AfterThrowing
            System.out.println("【环绕异常通知】---"+ methodName +"---【方法出现异常】,异常信息:" + e);
        } finally {
            //@After
            System.out.println("【环绕后置通知】---"+ methodName +"---【方法结束】");
        }


        //反射调用后的返回值也一定返回出去,不返回会空指针
        return proceed;
    }
 
 

二、环绕通知顺序&抛出异常让其他通知感受到

  当同时使用了环绕通知和普通通知,再来看一下执行顺序:

     /*
     * 环绕通知:是优先于普通通知执行,执行顺序:
     *
     *  普通通知:
     *  [普通前置]
     *  目标方法执行
     *  [普通后置]
     *  [普通方法返回/方法异常]
     *
     *
     *  普通通知+环绕通知
     *
     * 【普通前置】
     *
     *  {
     *  try{
     *      环绕前置
     *      环绕执行目标方法:目标方法执行
     *      环绕返回
     *  }catch(){
     *      环绕异常
     *  }finally
     *      环绕后置
     *      }
     *  }
     *  【普通后置】
     *  【普通方法返回/方法异常】
     *
     *
     *
     *  新的顺序:
     *      环绕前置 --- 普通前置 --- 目标方法执行 --- 环绕返回/异常 --- 环绕后置 --- 普通返回/异常 --- 普通后置
     *
     *
     *  注意:环绕通知的异常一定要抛出去
     *
     */
    @Around("myPoint()")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {

        String methodName = pjp.getSignature().getName();
        Object[] args = pjp.getArgs();
        Object proceed = null;
        try {
            //@Before
            System.out.println("【环绕前置通知】---"+ methodName +"---【方法开始】");
            //就是利用反射调用目标方法即可,就是 method.invoke(obj, args)
            proceed = pjp.proceed(args);
            //@AfterReturning
            System.out.println("【环绕返回通知】---"+ methodName +"---【方法返回,返回值 "+ proceed +"】");
        } catch (Exception e) {
            //@AfterThrowing
            System.out.println("【环绕异常通知】---"+ methodName +"---【方法出现异常】,异常信息:" + e);
            //为了让外界能知道这个异常,这个异常一定要抛出去
            throw new RuntimeException(e);
        } finally {
            //@After
            System.out.println("【环绕后置通知】---"+ methodName +"---【方法结束】");
        }


        //反射调用后的返回值也一定返回出去,不返回会空指针
        return proceed;
    }

  执行顺序:

  

  注意:环绕通知里面的异常一定要抛出去。

 

原文地址:https://www.cnblogs.com/niujifei/p/15450502.html