• 记一次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);
        }
    
    
    }
    
    

    通过上面的修改,我们可以根据自己的业务逻辑,去捕获对应的异常,最后返回合适的实体结果给调用方。

  • 相关阅读:
    linux安装mongo-c-driver
    DPDK在虚拟机上运行时,报错: Ethdev port_id=0 requested Rx offloads 0xe doesn't match Rx offloads capabilities 0x82a1d in rte_eth_dev_configure()
    用python写xml文件
    openvas在centos中扫描单项的python实现
    ARP协议的报文格式
    python装饰器使用
    openvas漏洞扫描:使用openvas时扫描漏洞时,报告中显示的数据与数据库数据不同
    单链表实现一元多项式乘法与加法运算(C语言)
    Java学习笔记DayN Java高级特性概况
    Java学习笔记Day5 集合
  • 原文地址:https://www.cnblogs.com/yiweiblog/p/13751062.html
Copyright © 2020-2023  润新知