簡體   English   中英

通過 Spring AOP + Aspectj 進行異常處理

[英]Exception handling through spring AOP + Aspectj

在我的項目中,我有一個基本上是 POJO 的域層和一個位於域層之上的 Spring 控制器/服務層。 我還有一個位於服務和域之間的 AOP 層。

我的域層正在拋出業務異常,這些異常現在正在服務層中處理。

但是我想改變它,以便從域層拋出的異常將在 AOP 層中處理。 AOP 層將某種錯誤響應並將其發送回 spring 控制器/Web 服務層。

我可以創建一個 IBizResponse 並為其創建兩個子類/接口,可能是 SuccessResponse 和 ErrorResponse,並使我的域層方法返回 IBizResponse。 但是我無法弄清楚如何讓 AOP 將 ErrorResponse 對象返回到服務層。

參見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) {
       // ...
     }

}

我遇到了同樣的情況,在發生任何異常處理的情況下,我必須返回錯誤響應 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);
    }
}

由於我無法共享實際代碼,因此稍微調整了代碼。 希望我把概念說清楚了。

考慮到 com.sc.bs.impl.* 是業務/領域層包,在 AOP 層使用 @Around 注解截取。 代碼片段:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM