浅谈微服务下异常处理

谈到微服务,必不可免就谈到spring cloud.

笔者正是基于spring cloud架构下的异常处理.

异常,按照业务划分下来,分为三类: 参数校验异常,自定义异常,以及系统异常.

参数校验异常: 通常是缺少参数,参数类型错误,以及相关校验不通过(javax.validation).

通常我们项目一开始,便定义了统一的基础异常类,和统一的错误码.

例如:

  • 成功: 2000
  • 缺少参数: 5001
  • 参数类型错误: 5002
  • 参数校验异常: 5003
  • 系统异常: 5000

基础异常类:

public abstract class BaseException extends RuntimeException {
    private String code = ResultCodeConstant.SYSTEM_ERROR;

    public Result getResult() {
        return Result.fail(this.code, this.getMessage() != null?this.getMessage():"error");
    }

    public BaseException() {
    }

    public BaseException(String message) {
        super(message);
    }

    public BaseException(String code, String message) {
        super(message);
        this.code = code;
    }

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

    public BaseException(Throwable cause) {
        super(cause);
    }

    public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

    public String getCode() {
        return this.code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

code常量类:

public class ResultCodeConstant {
    public static final String SUCCESS = "2000";//成功
    public static final String ARGUMENT_VANISH = "5001";//缺少参数
    public static final String ARGUMENT_TYPE_MISMATCH = "5002";//类型错误
    public static final String ARGUMENT_CONSTRAINT_VIOLATION = "5003";//参数校验错误
    public static final String SYSTEM_ERROR = "5000";
}

对外服务

为了达到对外服务的友好和保密,处理异常时,往往是拦截异常后返回友好结果.

首先约定了对外的结果的封装

public class Result<T> implements Serializable {
    private String code;
    private String desc;
    private T data;

    public T getData() {
        return this.data;
    }

    public Result(String code, String desc, T data) {
        this.code = code;
        this.desc = desc;
        this.data = data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public Result() {
    }

    public Result(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public String getCode() {
        return this.code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDesc() {
        return this.desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String toJsonString() {
        return JSONObject.toJSONString(this, new SerializerFeature[]{SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteDateUseDateFormat});
    }

    public static Result okDesc() {
        return new Result(ResultCodeConstant.SUCCESS, "成功");
    }

    public static Result okDesc(String desc) {
        return new Result(ResultCodeConstant.SUCCESS, desc);
    }

    public static Result ok(Object data) {
        return new Result(ResultCodeConstant.SUCCESS, "", data);
    }

    public static Result ok(String desc, Object data) {
        return new Result(ResultCodeConstant.SUCCESS, desc, data);
    }

    public static Result fail() {
        return new Result(ResultCodeConstant.SYSTEM_ERROR, "error");
    }

    public static Result fail(String dsec) {
        return new Result(ResultCodeConstant.SYSTEM_ERROR, dsec);
    }

    public static Result fail(String code, String dsec) {
        return new Result(code, dsec);
    }

    public static Result fail(String code, String dsec, Object data) {
        return new Result(code, dsec, data);
    }
}

在spring中,可以通过@ControllerAdvice来拦截controller中抛出的异常



/**
 * Created by wenshiliang on 2017/1/16.
 */
@ControllerAdvice()
@ConfigurationProperties
@Slf4j
public class GlobalExceptionHandler {



    @Autowired
    private CounterService counterService;

    public GlobalExceptionHandler() {
        log.info("GlobalExceptionHandler构建");
    }

    @ExceptionHandler(BaseException.class)
    @ResponseBody
    public Result baseExceptionHandler(BaseException e, HttpServletResponse response) {
        log.error("拦截自定义异常", e);
        counterService.increment("exception.custom");
        return e.getResult();
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public Result missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e,
                                                                 HttpServletResponse response) {
        log.warn("缺少参数", e);
        counterService.increment("exception.check");
        return Result.fail(ResultCodeConstant.ARGUMENT_VANISH,"缺少参数");
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public Result methodArgumentTypeMismatchExceptionExceptionHandler(MethodArgumentTypeMismatchException e,
                                                                      HttpServletResponse response) {
        log.warn("参数类型不正确", e);
        counterService.increment("exception.check");
        return Result.fail(ResultCodeConstant.ARGUMENT_TYPE_MISMATCH,"参数类型不正确");
    }


    /**
     * 参数校验异常
     *
     * @param e
     * @param response
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Result constraintViolationExceptionHandler(ConstraintViolationException e, HttpServletResponse response) {
        log.warn("参数校验异常", e);
        StringBuilder builder = new StringBuilder();
        Set<ConstraintViolation<?>> set = e.getConstraintViolations();
        if (set != null && set.size() > 0) {
            set.forEach(active -> {
                log.warn(active.getRootBeanClass() + active.getMessage());
                builder.append(active.getMessage()).append(".");
            });
        } else {
            builder.append("参数校验异常");
        }
        counterService.increment("exception.check");
        return Result.fail(ResultCodeConstant.ARGUMENT_CONSTRAINT_VIOLATION,builder.toString());
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Result BindException(BindException e, HttpServletResponse response) {
        log.warn("参数校验异常", e);
        counterService.increment("exception.check");
        String desc = e.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail(ResultCodeConstant.ARGUMENT_CONSTRAINT_VIOLATION, desc);
    }



    @ExceptionHandler//处理其他异常
    @ResponseBody //
    public Result exceptionHandler(Exception e, HttpServletResponse response) {
        Result result = null;
        log.error("拦截异常", e);
        counterService.increment("exception.system");
        result = Result.fail();
        return result;
    }
}

##对内服务

转载于:https://my.oschina.net/superwen/blog/1502954

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值