記一次SpringAOP環繞通知導致全局異常抓取失效的問題


背景

在web開發過程中,我們每個項目都必然會主動或者被動的拋出各種各樣的異常,那么如果拋出到最上層還沒有捕獲,那么就會導致程序停止。所以,一般我們在開發中都會使用全局異常捕獲機制,捕獲各種各樣的異常,最后返回統一的結果實體類給調用方。
另一方面,我們在使用spring框架開發的過程中,也會使用到aop來記錄日志或者一些與業務無關的信息。我在使用aop的環繞通知記錄接口請求時間時,遇到全局異常處理失效的問題。 導致前端在調用結束后,接口請求正常,但是卻獲取不到全局異常處理的結果。

全局異常處理代碼

/**
 * 全局捕獲異常的類,返回信息給瀏覽器,可以自定義返回的code,msg等信息
 */
@ControllerAdvice
public class ApiExceptionHandle {
    private static final Logger logger = LoggerFactory.getLogger(ApiExceptionHandle.class);

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ApiResult handle(Exception e) {
        logger.error("全局異常:{},{}", e.getMessage(), e);
        return ResultUtil.handleApiException(e);
    }
}

AOP記錄接口請求時間的代碼

@Aspect
@Service
public class SubReqAop {
    private static final Logger logger = LoggerFactory.getLogger(SubReqAop.class);

    @Autowired
    private SubReqDomainService subReqDomainService;

    //切入所有以schedule開頭的方法,計算排程時間
    @Pointcut("execution(* com.hierway.schedm.schedService.impl.ScheduleBusinessImpl.schedule*(..))")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        long startTime = System.currentTimeMillis();
        Object proceed = null;
        try {
            proceed = joinPoint.proceed(args);//調用業務代碼
            long endTime = System.currentTimeMillis();
            ApiResult result = (ApiResult) proceed;
            if (ResultCode.SUCCESS.getCode().equals(result.getCode())) {
                SubreqDoneinfo build = SubreqDoneinfo.builder().createtime(new Date()).spendtime((int) (endTime - startTime)).build();
                subReqDomainService.insertDoneInfo(build);
            }
        }catch (Throwable throwable){
            throwable.printStackTrace();
        }
        return proceed;
    }

}

上面通過proceed調用業務邏輯代碼,因為業務邏輯中可能會拋出自定義異常,如:參數錯誤。如果調用過程中出現異常,將導致proceed返回的給調用方的值為null。

修改之后的AOP記錄接口請求時間的代碼

/**
 * @ClassName: SubReqAop
 * @Description: 記錄Schedule花費多長時間的AOP
 * @Author: sunyiwei
 * @Date: 2019/9/10 15:23
 */
@Aspect
@Service
public class SubReqAop {
    private static final Logger logger = LoggerFactory.getLogger(SubReqAop.class);

    @Autowired
    private SubReqDomainService subReqDomainService;

    //切入所有以schedule開頭的方法,計算排程時間
    @Pointcut("execution(* com.hierway.schedm.schedService.impl.ScheduleBusinessImpl.schedule*(..))")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        long startTime = System.currentTimeMillis();
        Object proceed = null;
        try {
            proceed = joinPoint.proceed(args);
            long endTime = System.currentTimeMillis();
            ApiResult result = (ApiResult) proceed;
            if (ResultCode.SUCCESS.getCode().equals(result.getCode())) {
                SubreqDoneinfo build = SubreqDoneinfo.builder().createtime(new Date()).spendtime((int) (endTime - startTime)).build();
                subReqDomainService.insertDoneInfo(build);
            }
            return proceed;
        } catch (ApiException e) {
            //如果是自定義的異常都將捕獲,並通過handleApiException方法轉換為對應的實體類
            logger.error("SubReqAop異常了");
            e.printStackTrace();
            return ResultUtil.handleApiException(e);
        }catch (Throwable throwable){
            throwable.printStackTrace();
        }
        return ResultUtil.error(ResultCode.UNKONW_ERROR);
    }


}

通過上面的修改,我們可以根據自己的業務邏輯,去捕獲對應的異常,最后返回合適的實體結果給調用方。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM