【问题标题】:Exception handling through spring AOP + Aspectj通过 spring AOP + Aspectj 处理异常
【发布时间】:2014-09-07 22:45:09
【问题描述】:

在我的项目中,我有一个基本上是 POJO 的域层和一个位于域层之上的 Spring 控制器/服务层。我还有一个位于服务和域之间的 AOP 层。

我的领域层正在抛出业务异常,现在正在服务层中处理。

但是我想更改它,以便从域层抛出的异常将在 AOP 层中处理。 AOP 层会做出某种错误响应并将其发送回 Spring 控制器/Web 服务层。

我可以创建一个 IBizResponse 并为其创建两个子类/接口,可能是 SuccessResponse 和 ErrorResponse,并使我的域层方法返回 IBizResponse。但是我无法弄清楚如何让 AOP 将 ErrorResponse 对象返回给服务层。

【问题讨论】:

    标签: java spring aop aspectj spring-aop


    【解决方案1】:

    我遇到了同样的情况,在处理任何异常时我必须返回错误响应 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】:

      参见https://docs.spring.io/spring/docs/4.1.0.RELEASE/spring-framework-reference/htmlsingle/#aop-introduction-defn的投掷建议部分

      当匹配的方法执行通过抛出异常退出时,抛出通知运行后。它是使用@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】:

        考虑到 com.sc.bs.impl.* 是业务/领域层封装,在AOP层使用@Around注解截取。代码sn-p:

        @Around("execution(* com.sc.bs.impl..*.*(..))")
        public Object exceptionHandlerWithReturnType(ProceedingJoinPoint joinPoint) throws Throwable{
            try {
                obj = joinPoint.proceed();
            } catch(Exception ex) {
                throw ex;
            }
        }
        

        【讨论】:

        • 你的 try catch 有点没用不是吗?
        • 是的,但我用于其他目的,如审计和事务提交和回滚。
        猜你喜欢
        • 1970-01-01
        • 2017-01-27
        • 2012-06-12
        • 2015-12-17
        • 1970-01-01
        • 2010-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多