美文网首页
# Spring实战系列 - Aspect 五种通知切面通知执行

# Spring实战系列 - Aspect 五种通知切面通知执行

作者: 柳经年 | 来源:发表于2020-04-22 11:24 被阅读0次

    日常开发中经常会使用到 Spring AOP,通知类型有:Around、Before、After、AfterReturning、AfterThrowing ,本文主要讲解五种通知都有时,正常和异常情况下的执行顺序,以及多个切面存在时,执行顺序如何

    正常逻辑代码

    • 接口定义如下
    public interface UserService {
    
        void saveUser();
    
        void deleteUser();
    }
    
    • 接口实现代码如下
    @Slf4j
    @Component
    public class UserServiceImpl implements UserService {
    
        @Override
        public void saveUser() {
            log.info("save user");
        }
    
        @Override
        public void deleteUser() {
            log.info("delete user");
            System.out.println(1 / 0);
        }
    }
    

    针对正常接口 UserService 定义两个切面逻辑

    • 切面一
    @Slf4j
    @Order(99)// 注意顺序
    @Aspect
    @Component
    public class UserServiceAspect {
    
        @Before("execution(* com.lushwe.aspect.service.impl..*(..))")
        public void before() {
            log.info("before");
        }
    
        @Around("execution(* com.lushwe.aspect.service.impl..*(..))")
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            log.info("around开始");
            Object proceed = proceedingJoinPoint.proceed();
            log.info("around结束");
            return proceed;
        }
    
        @After("execution(* com.lushwe.aspect.service.impl..*(..))")
        public void after() {
            log.info("after");
        }
    
        @AfterReturning("execution(* com.lushwe.aspect.service.impl..*(..))")
        public void afterReturning() {
            log.info("afterReturning");
        }
    
        @AfterThrowing("execution(* com.lushwe.aspect.service.impl..*(..))")
        public void afterThrowing() {
            log.info("afterThrowing");
        }
    }
    
    • 切面二
    @Slf4j
    @Order(100)// 注意顺序
    @Aspect
    @Component
    public class UserServiceAspectTwo {
    
        @Before("execution(* com.lushwe.aspect.service.impl..*(..))")
        public void before() {
            log.info("before");
        }
    
        @Around("execution(* com.lushwe.aspect.service.impl..*(..))")
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            log.info("around开始");
            Object proceed = proceedingJoinPoint.proceed();
            log.info("around结束");
            return proceed;
        }
    
        @After("execution(* com.lushwe.aspect.service.impl..*(..))")
        public void after() {
            log.info("after");
        }
    
        @AfterReturning("execution(* com.lushwe.aspect.service.impl..*(..))")
        public void afterReturning() {
            log.info("afterReturning");
        }
    
        @AfterThrowing("execution(* com.lushwe.aspect.service.impl..*(..))")
        public void afterThrowing() {
            log.info("afterThrowing");
        }
    }
    

    正常情况下执行顺序,打印日志如下

    2020-04-17 15:27:55.500  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspect      : around开始
    2020-04-17 15:27:55.501  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspect      : before
    2020-04-17 15:27:55.501  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : around开始
    2020-04-17 15:27:55.501  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : before
    2020-04-17 15:27:55.501  INFO 4329 --- [           main] c.l.aspect.service.impl.UserServiceImpl  : save user
    2020-04-17 15:27:55.503  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : around结束
    2020-04-17 15:27:55.503  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : after
    2020-04-17 15:27:55.503  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : afterReturning
    2020-04-17 15:27:55.503  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspect      : around结束
    2020-04-17 15:27:55.503  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspect      : after
    2020-04-17 15:27:55.503  INFO 4329 --- [           main] com.lushwe.aspect.UserServiceAspect      : afterReturning
    

    有异常情况下执行顺序,打印日志如下

    2020-04-17 15:20:55.403  INFO 4227 --- [           main] com.lushwe.aspect.UserServiceAspect      : around开始
    2020-04-17 15:20:55.403  INFO 4227 --- [           main] com.lushwe.aspect.UserServiceAspect      : before
    2020-04-17 15:20:55.403  INFO 4227 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : around开始
    2020-04-17 15:20:55.403  INFO 4227 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : before
    2020-04-17 15:20:55.403  INFO 4227 --- [           main] c.l.aspect.service.impl.UserServiceImpl  : delete user
    2020-04-17 15:20:55.403  INFO 4227 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : after
    2020-04-17 15:20:55.405  INFO 4227 --- [           main] com.lushwe.aspect.UserServiceAspectTwo   : afterThrowing
    2020-04-17 15:20:55.405  INFO 4227 --- [           main] com.lushwe.aspect.UserServiceAspect      : after
    2020-04-17 15:20:55.406  INFO 4227 --- [           main] com.lushwe.aspect.UserServiceAspect      : afterThrowing
    Exception in thread "main" java.lang.ArithmeticException: / by zero
    ...(详细异常信息省略)...
    

    总结

    • 正常情况下执行顺序:Around start -> Before -> Around end -> After -> AfterReturning
    • 有异常情况下执行顺序:Around start -> Before -> After -> AfterThrowing ,有异常时,Around end 逻辑不会执行
    • 当有多有切面时,按照 @Order 顺序依次执行,从上面日志可以看出

    • 本文完,希望对你有帮助

    相关文章

      网友评论

          本文标题:# Spring实战系列 - Aspect 五种通知切面通知执行

          本文链接:https://www.haomeiwen.com/subject/umnbihtx.html