皬Spring実戦シリーズ-Asppectの5種類の通知の実施順序


日常開発ではSpring AOPによく使われていますが、通知の種類はAround、Before、After、AfterReturning、AfterThrowingです.ここでは主に5つの通知を説明します.正常と異常の場合の実行順序と、複数の切断面が存在する場合の実行順序はどうなりますか?
通常の論理コード
  • インターフェースの定義は以下の通りです.
    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に対して2つの断面論理を定義する.
  • うどん1
  • @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の順に順次実行します.上記のログから
  • が分かります.
  • 本の文章が終わりました.助けてほしいです.