通过Spring AOP+AspectJ进行异常处理

watbbzwu  于 2022-10-04  发布在  Spring
关注(0)|答案(4)|浏览(172)

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

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

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

我可以创建一个IBizResponse并创建它的两个子类/接口,可能是一个SuccessResponse和一个ErrorResponse,然后让我的域层方法返回IBizResponse。但是,我想不出如何让AOP将ErrorResponse对象返回给服务层。

iih3973s

iih3973s1#

请参阅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) {
       // ...
     }

}
kx5bkwkv

kx5bkwkv2#

我遇到了相同的场景,在任何异常处理的情况下,我必须返回错误响应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);
    }
}

调整了代码,因为我不能分享实际的代码。希望我把概念讲清楚了。

rqmkfv5c

rqmkfv5c3#

考虑到com.sc.bs.imp.*是业务/域层的包,并在AOP层使用@Above注解拦截它。代码片段:

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

xwbd5t1u4#

考虑使用@ExceptionHandler和@ControllerAdiance的全局异常处理程序

创建一个CustomExceptionHandler。在类级别添加@ControllerAdtendant注解。并为您想要处理的每个异常添加@ExceptionHandler注解。记住@ExceptionHandler的顺序很重要--一旦它与一个异常匹配,它就不会继续检查后面的处理程序。

// in CustomExceptionHandler

@ControllerAdvice
public class CustomExceptionHandler{

    @ExceptionHandler(value = {NullPointerException.class})
    public ResponseEntity<ErrorResponse> handleDemoNotFoundException(NullPointerExceptione){
        return new ResponseEntity(ErrorResponse.builder().message("Null Pointer").build(), HttpStatus.OK);
    }

    @ExceptionHandler(value = {Exception.class})
    public ResponseEntity handleException(Exception e){
        return new ResponseEntity(ErrorResponse.builder().message(e.getMessage()).build(), HttpStatus.OK);
    }

}

我的其他类以供参考和测试

// ErrorResponse Class. I am using lombok

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {
    private String message;
}

// controller
@RestController
public class DemoController {

    @GetMapping("/exception")
    public ResponseEntity<MyResponse> errorDemoEndPoint() throws NullPointerException {
        MyResponse response = MyResponse.builder().build();
        throw new NullPointerException("Null Pointer");
        return ResponseEntity.ok(response);
    }
}

相关问题