SpringBoot项目中异常的捕获和处理

Posted sysu_lluozh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot项目中异常的捕获和处理相关的知识,希望对你有一定的参考价值。

一般在开发中,会有业务异常和程序异常两种

一、异常处理的意义

程序中往往在try-catch异常的时候会进行重新抛出一个新的异常,如何捕获和处理异常在编码过程中具有重要的意义

  • 提高健壮性,提前对可能发生的异常情况预判处理提高稳定性和可用性
    如,预判网路异常然后在异常处理中进行重试
  • 利于错误恢复和错误处理,针对不同的异常进行不同的处理
  • 有利于发生异常时问题的排查和解决
    如,通过logger可以知道错误发生的地方、错误详情等信息

如何处理异常信息可以提高代码的健壮性、稳定性和可用性等,接下来看看业务中如何进行异常的捕获和处理

二、定义错误码

首先需要自定义业务中错误状态码,方便状态码的管理

ErrorCodeEnum.java

package com.lluozh.fagent.config;

public enum ErrorCodeEnum {

    /* 规范:错误码长度6位,单个领域前缀为前三位 */

    /* 通用异常: 100xxx */
    PARAM_INVALID(100001, "参数校验异常"),
    NULL_POINTER(100002, "空指针异常")
    UNKNOWN_ERROR(199999, "未知异常"),
	
	/* 场景执行异常: 200xxx */
    SCENE_JMX_EXECUTE_ERROR(200001, "场景执行异常");


    private final int code;
    private final String msg;

    ErrorCodeEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

三、自定义异常类

不同的业务异常有可能有特定的处理逻辑,故除了需要定义通用的异常类,还需要根据业务的需求定义不同的业务自定义异常类

3.1 通用异常类

BizException.java

package com.lluozh.fagent.exception;

import lombok.extern.slf4j.Slf4j;
import com.lluozh.fagent.config.ErrorCodeEnum;

@Slf4j
public class BizException extends Exception {

    private static final long serialVersionUID = 1L;
    

    public BizException() {
        super("");
    }

    public BizException(String message, Throwable cause) {
        super(message, cause);
    }

    public BizException(String msg) {
        super(msg);
    }

}

3.2 业务自定义异常类

JmxExecuteException.java

package com.lluozh.fagent.exception;

import lombok.extern.slf4j.Slf4j;
import com.lluozh.fagent.config.ErrorCodeEnum;

@Slf4j
public class JmxExecuteException extends Exception {

    private static final long serialVersionUID = 1L;
    

    public JmxExecuteException() {
        super("场景执行异常");
    }

    public JmxExecuteException(String message, Throwable cause) {
        super(message, cause);
    }

    public JmxExecuteException(String msg) {
        super(msg);
    }
    
    public int getCode() {
        return ErrorCodeEnum.PARAM_INVALID.getCode();
    }
    
    public String getErrorMsg() {
        return ErrorCodeEnum.PARAM_INVALID.getMsg();
    }

}

四、定义异常捕获业务处理

有些异常类需要在捕获异常后处理一些特定的业务逻辑,比如下面场景执行异常捕获这个业务逻辑中,捕获到异常后需要变更场景执行的状态和节点的状态,故需要在异常捕获后使用切面的方式自定义部分异常处理逻辑

ExceptionHandlers.java

package com.lluozh.fagent.handler;

import com.lluozh.service.support.ApiResult;
import com.lluozh.fagent.service.SceneService;
import com.lluozh.fagent.entity.SceneStatusEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;

/**
 * @author lluozh
 * @Description:
 * @date 2021/8/27
 */
@Slf4j
@ControllerAdvice
public class ExceptionHandlers {

    @Autowired
    private SceneService sceneService;

    /**
     * 场景执行异常捕获
     * @return
     */
    @ExceptionHandler(value = JmxExecuteException.class)
    @ResponseBody
    public ApiResult<Void> handleJmxExecuteExceptionHandler(Exception e) {
    	log.error("场景执行异常!原因是:",e);
        // 更新scene执行状态
        sceneService.sceneStatusAlter(SceneStatusEntity.ExecStatus.ERROR, e.toString());

        return ApiResult.fail(ErrorCodeEnum.SCENE_JMX_EXECUTE_ERROR.getCode(), e.getMessage());
    }

    /**
     * 空指针的异常
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public ApiResult<Void> nullPointerExceptionHandler(Exception e) {
        log.error("发生空指针异常!原因是:",e);
        return ApiResult.fail(ErrorCodeEnum.NULL_POINTER.getCode(), ErrorCodeEnum.NULL_POINTER.getMsg());
    }

    /**
     * 参数错误异常
     * @return
     */
    @ExceptionHandler(value= IllegalArgumentException.class)
    @ResponseBody
    public ApiResult<Void> illegalArgumentExceptionHandler(HttpServletRequest req, IllegalArgumentException e) {
        log.error("发生参数错误异常!原因是:", e);
        return ApiResult.fail(ErrorCodeEnum.PARAM_INVALID.getCode(), ErrorCodeEnum.PARAM_INVALID.getMsg());
    }

    /**
     * 未知异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ApiResult<Void> handleException(Exception e) {
        return ApiResult.fail(ErrorCodeEnum.UNKNOWN_ERROR.getCode(), e.toString());
    }

}

五、使用示例

JmeterExecuteEngine.java

package com.lluozh.fagent.jmeter.engine;

import com.lluozh.fagent.exception.JmxExecuteException;

// 加载执行的jmx文件
HashTree jmxTree;
try {
    jmxTree = SaveService.loadTree(jmxFile);
} catch (Exception e) {
    throw new JmxExecuteException("【JmxExecuteException】agent加载jmx文件异常!", e);
}

以上是关于SpringBoot项目中异常的捕获和处理的主要内容,如果未能解决你的问题,请参考以下文章

springboot中添加全局异常捕获类

异常和TCP通讯

聊聊springboot项目全局异常处理那些事儿

Java异常处理机制

小编教您Springboot项目中异常拦截设计与处理

spring-- springboot配置全局异常处理器