복붙노트

[SPRING] 봄 AOP + Aspectj를 통한 예외 처리

SPRING

봄 AOP + Aspectj를 통한 예외 처리

내 프로젝트에는 기본적으로 POJO 인 도메인 계층과 도메인 계층의 맨 위에있는 Spring 컨트롤러 / 서비스 계층이 있습니다. 나는 또한 서비스와 도메인 사이에 앉아있는 AOP 레이어를 가지고있다.

내 도메인 계층이 이제 서비스 계층에서 처리되고있는 비즈니스 예외를 던지고 있습니다.

그러나 도메인 계층에서 throw 된 예외가 AOP 계층에서 처리 될 수 있도록이를 변경하려고합니다. AOP 레이어는 어떤 종류의 오류 응답을 보내고 스프링 컨트롤러 / 웹 서비스 레이어로 다시 보냅니다.

IBizResponse를 만들고 두 개의 하위 클래스 / 인터페이스를 만들고 SuccessResponse와 ErrorResponse를 만들고 내 도메인 계층 메서드가 IBizResponse를 반환하도록 할 수 있습니다. 그러나 AOP를 ErrorResponse 객체를 서비스 계층에 반환하는 방법을 이해할 수는 없습니다.

해결법

  1. ==============================

    1.나는 예외 처리의 경우 오류 응답 DTO를 리턴해야만했던 동일한 시나리오를 발견했다. @Aspect 클래스 내부,

    나는 예외 처리의 경우 오류 응답 DTO를 리턴해야만했던 동일한 시나리오를 발견했다. @Aspect 클래스 내부,

    @Aspect
    @Component
    public class MyAspect{
    
        private static final Logger LOGGER = LoggerFactory.getLogger(MyAspect.class);
    
        @Pointcut("execution(* com.linda.dao.strategy.*.*(..))")
        public void strategyMethods() { }
    
        @Pointcut("execution(* com.linda.controller.*.*(..)) || execution(* com.linda.Manager.*(..))")
        public void controllerMethods(){  }
    
        @Around("strategyMethods()")
        public Object profileStrategyMethods(ProceedingJoinPoint pjp) throws Throwable {
    
            long start = System.currentTimeMillis();
            Object output = null;
            LOGGER.info("Class:"+pjp.getTarget().getClass()+" entry -> method ->"+pjp.getSignature().getName());
            try{
                output = pjp.proceed();
                long elapsedTime = System.currentTimeMillis() - start;
                LOGGER.info("Method execution time: " + elapsedTime + " milliseconds.");
                LOGGER.info("Class:"+pjp.getTarget().getClass()+" exit -> method ->"+pjp.getSignature().getName());
            }catch(Throwable t){
                throw new InternalServerException(t.getMessage());  
            }
    
            return output;
        }
    
        @AfterThrowing(pointcut="execution(* com.linda.dao.strategy.*.*(..)) || execution(* com.linda.controller.*.*(..)) || execution(* com.linda.Manager.*(..))",throwing = "ex")
        public void doRecoveryActions(JoinPoint joinPoint, Throwable ex) {
    
            Signature signature = joinPoint.getSignature();
            String methodName = signature.getName();
            String stuff = signature.toString();
            String arguments = Arrays.toString(joinPoint.getArgs());
            LOGGER.error("Write something in the log... We have caught exception in method: "
                    + methodName + " with arguments "
                    + arguments + "\nand the full toString: " + stuff + "\nthe exception is: "
                    + ex.getMessage());
        }
    }
    

    아래처럼 예외 처리를위한 다른 클래스를 정의했습니다 :

    @ControllerAdvice
    public class ExceptionLogAdvice {
    
        @ExceptionHandler(InternalServerException.class)
        @ResponseStatus(HttpStatus.BAD_GATEWAY)
        @ResponseBody
        public ResponseEntity<Object> handleValidationException(final InternalServerException internalServerException){
    
            ErrorResponseDTO dto = constructErrorResponse(internalServerException);
            return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(dto);
        }
    }
    

    실제 코드를 공유 할 수 없기 때문에 코드를 조금 트윗했습니다. 희망을 나는 개념을 분명히했다.

  2. ==============================

    2.https://docs.spring.io/spring/docs/4.1.0.RELEASE/spring-framework-reference/htmlsingle/#aop-introduction-defn의 조언을 던진 후를 참조하십시오.

    https://docs.spring.io/spring/docs/4.1.0.RELEASE/spring-framework-reference/htmlsingle/#aop-introduction-defn의 조언을 던진 후를 참조하십시오.

    예외를 throw하여 일치하는 메소드 실행이 종료 될 때 조언을 실행 한 후 실행됩니다. @AfterThrowing 주석을 사용하여 선언됩니다.

    예제들

    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.AfterThrowing;
    
    @Aspect
    public class AfterThrowingExample {
    
       @AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
       public void doRecoveryActions() {
         // ...
        }
    
    }
    
    
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.AfterThrowing;
    
    @Aspect
    public class AfterThrowingExample {
    
        @AfterThrowing(
        pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
        throwing="ex")
        public void doRecoveryActions(DataAccessException ex) {
           // ...
         }
    
    }
    
  3. ==============================

    3.고려 com.sc.bs.impl. * 비즈니스 / 도메인 계층 패키지이며 @Around 주석을 사용하여 AOP 레이어에서 도청. 코드 스 니펫 :

    고려 com.sc.bs.impl. * 비즈니스 / 도메인 계층 패키지이며 @Around 주석을 사용하여 AOP 레이어에서 도청. 코드 스 니펫 :

    @Around("execution(* com.sc.bs.impl..*.*(..))")
    public Object exceptionHandlerWithReturnType(ProceedingJoinPoint joinPoint) throws Throwable{
        try {
            obj = joinPoint.proceed();
        } catch(Exception ex) {
            throw ex;
        }
    }
    
  4. from https://stackoverflow.com/questions/24797157/exception-handling-through-spring-aop-aspectj by cc-by-sa and MIT license