随笔 - 1162  文章 - 0  评论 - 16  阅读 - 59万 

一、多切面的执行顺序

  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,环绕只是影响当前切面

    图解:

      

 

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

 

posted on   格物致知_Tony  阅读(527)  评论(0编辑  收藏  举报
编辑推荐:
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?
点击右上角即可分享
微信分享提示

目录导航