• (III)AOP:第八节:多切面运行顺序


    一、多切面的执行顺序

      1、切面中只有普通通知

        BValidateAspect切面:

    @Aspect
    @Component
    public class BValidataAspect {
    
    
    
        @Before("com.njf.aop.utils.LogUtils.myPoint()")
        public static void logStart(JoinPoint joinpoint){
            Object[] args = joinpoint.getArgs();
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[Validata前置通知]【"+ methodName +"】方法执行了,参数为【"+ Arrays.toString(args) +"】");
        }
    
        @AfterReturning(value = "com.njf.aop.utils.LogUtils.myPoint()", returning = "result")
        public static void logReturn(JoinPoint joinpoint, Object result){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[Validata返回通知]【"+ methodName +"】方法执行完成,他的结果为是:" + result);
        }
    
        @AfterThrowing(value = "com.njf.aop.utils.LogUtils.myPoint()", throwing = "exception")
        public static void logException(JoinPoint joinpoint, Exception exception){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[Validata异常通知]【"+ methodName +"】方法出现了异常,异常为: " + exception.getCause());
        }
    
        @After(value = "com.njf.aop.utils.LogUtils.myPoint()")
        public static void logEnd(JoinPoint joinpoint){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[Validata后置通知]【"+ methodName +"】方法执行最终完成");
        }
    
    }

        LogUtils 切面:

    @Aspect
    @Component
    public class LogUtils {
    
        @Pointcut("execution(public int com.njf.aop.calc.MyMathCalculator.*(int, int))")
        public void myPoint(){}
    
        @Before("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
        public static void logStart(JoinPoint joinpoint){
            Object[] args = joinpoint.getArgs();
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[LogUtils前置通知]【"+ methodName +"】方法执行了,参数为【"+ Arrays.toString(args) +"】");
        }
    
        //想在目标方法正执行完毕之后
        @AfterReturning(value = "execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))", returning = "result")
        public static void logReturn(JoinPoint joinpoint, Object result){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[LogUtils返回通知]【"+ methodName +"】方法执行完成,他的结果为是:" + result);
        }
    
        @AfterThrowing(value = "execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))", throwing = "exception")
        //想在目标方法出现异常时执行
        public static void logException(JoinPoint joinpoint, Exception exception){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[LogUtils异常通知]【"+ methodName +"】方法出现了异常,异常为: " + exception.getCause());
        }
    
        //想在目标方法结束时执行
        @After("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
        public static void logEnd(JoinPoint joinpoint){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[LogUtils后置通知]【"+ methodName +"】方法执行最终完成");
        }

        测试运行:

        

         可以发现是 ValidataAspect 切面先执行前置,然后 LogUtils 前置,然后继续 LogUtils 里面的后置与返回,最后是 ValidataAspect 的后置与返回。

         图解:

          

        注意:切面的顺序是按照类名的字母顺序来执行的。

      2、使用注解指定切面运行顺序

      (1)在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级是不确定的;
      (2)切面的优先级可以通过实现 Ordered 接口或利用 @Order 注解指定;
      (3)实现 Ordered 接口,getOrder() 方法的返回值越小,优先级越高;
      (4)若使用 @Order 注解,序号出现在注解中
      (5)@Order(1),定义切面作用的优先级,值越小优先级越高,默认值为int的最大值
        案例:
    @Component  
    @Aspect
    @Order(0)          //该切面先执行,序号越小,越先执行
    public class TestAspect {
         
         @Before(value = "execution(public int  com.spring.aop.ICalc.add(int, int))")
         public void beforeMethod(JoinPoint joinPoint) {
             System.out.println("方法之前之前======");
         }
         
    }
    
    @Component   
    @Aspect  
    @Order(1)        //该切面后执行
    public class LoggerAspect {
         @Before(value = "execution(public int  com.spring.aop.ICalc.add(int, int))")
         public void beforeMethod(JoinPoint joinPoint) {
             System.out.println("方法执行之前");
             Object[] args = joinPoint.getArgs();   //获取方法的参数
             String methodName =  joinPoint.getSignature().getName();  //获取方法名
             System.out.println("方法名:" + methodName +  ",参数:" + Arrays.toString(args));
         }
    }

      3、加入环绕通知

        在 LogUtils 类中添加环绕通知,并且添加 @Order注解指定运行顺序

        LogUtils类:

    @Aspect
    @Component
    @Order(1)
    public class LogUtils {
    
        @Pointcut("execution(public int com.njf.aop.calc.MyMathCalculator.*(int, int))")
        public void myPoint(){}
        
        @Before("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
        public static void logStart(JoinPoint joinpoint){
            Object[] args = joinpoint.getArgs();
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[LogUtils前置通知]【"+ methodName +"】方法执行了,参数为【"+ Arrays.toString(args) +"】");
        }
    
        //想在目标方法正执行完毕之后
        @AfterReturning(value = "execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))", returning = "result")
        public static void logReturn(JoinPoint joinpoint, Object result){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[LogUtils返回通知]【"+ methodName +"】方法执行完成,他的结果为是:" + result);
        }
    
        @AfterThrowing(value = "execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))", throwing = "exception")
        //想在目标方法出现异常时执行
        public static void logException(JoinPoint joinpoint, Exception exception){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[LogUtils异常通知]【"+ methodName +"】方法出现了异常,异常为: " + exception.getCause());
        }
    
        //想在目标方法结束时执行
        @After("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))")
        public static void logEnd(JoinPoint joinpoint){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[LogUtils后置通知]【"+ methodName +"】方法执行最终完成");
        }
        @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;
        }
    }

        BValidataAspect 类:

    @Aspect
    @Component
    @Order(2)
    public class BValidataAspect {
    
    
        @Before("com.njf.aop.utils.LogUtils.myPoint()")
        public static void logStart(JoinPoint joinpoint){
            Object[] args = joinpoint.getArgs();
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[Validata前置通知]【"+ methodName +"】方法执行了,参数为【"+ Arrays.toString(args) +"】");
        }
    
        @AfterReturning(value = "com.njf.aop.utils.LogUtils.myPoint()", returning = "result")
        public static void logReturn(JoinPoint joinpoint, Object result){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[Validata返回通知]【"+ methodName +"】方法执行完成,他的结果为是:" + result);
        }
    
        @AfterThrowing(value = "com.njf.aop.utils.LogUtils.myPoint()", throwing = "exception")
        public static void logException(JoinPoint joinpoint, Exception exception){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[Validata异常通知]【"+ methodName +"】方法出现了异常,异常为: " + exception.getCause());
        }
    
        @After(value = "com.njf.aop.utils.LogUtils.myPoint()")
        public static void logEnd(JoinPoint joinpoint){
            String methodName = joinpoint.getSignature().getName();
            System.out.println("[Validata后置通知]【"+ methodName +"】方法执行最终完成");
        }
    
    }

        测试运行:

        

        LogUtils 类中加入了环绕通知,不会影响 BValidataAspect,环绕只是影响当前切面

        图解:

          

        先执行各切面的前置,再执行目标方法,根据从内到外的顺序执行,(环绕只影响添加它的切面,且他在添加它的前面中优先级高)

  • 相关阅读:
    React同构直出优化总结
    Kubenertes资源分配之Request和Limit解析
    Node Server零基础——开发环境文件自动重载
    Vue组件开发实践之scopedSlot的传递
    【干货合集】Docker快速入门与进阶
    ES6 中的 Set
    十个书写Node.js REST API的最佳实践(上)
    oozie配置安装与原理
    Livy原理详解
    阿里(蚂蚁金服)招聘
  • 原文地址:https://www.cnblogs.com/niujifei/p/15452020.html
Copyright © 2020-2023  润新知