spring boot实战之异常处理
2017-09-30 本文已影响176人
思与学
异常处理是一个比较基础而又重要的技能点,在团队内最好形成一个统一的规则,避免团队成员不断掉进前辈已经爬出来的坑中。
1、全局异常处理
spring boot支持配置全局异常处理,记录未捕获的全局异常,这样方便在问题发生时快速定位问题,配置方式如下:
@ControllerAdvice
public class GlobalDefaultExceptionHandler {
private static Logger logger = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String, Object> defaultErrorHandler(HttpServletRequest req,HttpServletResponse response, Exception e) {
logger.error("defaultErrorHandler:", e);
response.setStatus(500);
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", "-1000");
map.put("msg", "系统繁忙");
return map;
}
}
- 在类上添加@ControllerAdvice注释
- 根据异常类型创建不同的方法,在方法上添加@ExceptionHandler注解,value的值是具体的异常类型
- defaultErrorHandler方法的返回值可以是String(view路径),Map(json结构,需添加@ResponseBody注解)
- response状态需要设置,否则前端看到的会是正常的200,根据具体的异常来设置,如无权限返回403等,两种设置方式,response.setStatus(500) 或者 @ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)注解
2、for、while循环异常处理
在for、while循环内是否需要进行异常捕获应该根据循环体的业务来确定,当一次循环过程中发生异常时,是否要终止循环,这是你使用循环时不能忽略的一点。
如以下场景:
- APP批量上传用户启动、使用事件,循环将每条数据处理后放入kafka队列:每次循环都是一个独立的处理过程,一次循环发生异常时不希望终止整个循环,类似的场景循环内部就需要进行异常捕获,从而避免一条数据的异常导致整批数据一起失败;
- 批量删除用户,全部成功,否则回滚:业务需求是整个批次的数据全部成功,一个失败整体失败,那么就不需要在循环体内部进行异常捕获了,可以在循环体外或依赖全局异常处理来记录异常信息;
在循环内部捕获异常,特别是while循环时,要注意循环终止条件,不要出现无限循环记录日志,导致磁盘写满的情况。
3、代码段异常处理
完成一件事情,需要执行很多步处理,编程时我们通常使用一个空行来分割不同的“步”以使程序看起来更有调理,每一步的操作可以定义为一个粗粒度的“代码段”。一个代码段是否需要进行异常捕获,同样是有代码的业务来确定,当异常发生时,是否需要终止整个处理流程是判断的标准。
如以下场景:
- 用户调用A接口,接口A包含三个代码段,参数校验->请求信息放入kafka->返回请求结果:第二步“请求信息放入kafka”对整个接口来说属于附加操作,当它发生异常时不应该影响用户正常获取数据,故此该代码段需要添加异常捕获,避免非核心业务的异常影响核心业务的执行。
- 用户调用B接口,接口B包含是哪个代码段,参数校验->创建用户信息—>创建用户账号信息,第二步和第三步任何一个发生异常,都会导致整个操作失败,这种场景就不能单纯的捕获异常,那样会导致数据的不一致。
4、异常日志记录
异常日志要记录在日志文件内,一定不要简单的将日志打印到控制台(测试环境一个tomcat放了十几个项目,如果都打印到控制台...),在项目后期可以全局搜索System.out和System.err,并向对应人员指出。spring boot内建议使用logback作为日志组件,日志的使用可参考sprign boot项目实战:日志;
5、总结
- 项目内建议配置全局异常捕获,有利于问题排查;
- 单次循环发生异常是否应该终止循环?不要忽略这个的问题;
- 注意循环终止条件,避免出现无限循环记录日志的情况
- 一个代码段发生异常是否要终止整个处理流程?同样不要忽略这个问题;
- 异常日志最好记录在日志文件内,不要简单的打印到控制台
本人搭建好的spring boot web后端开发框架已上传至GitHub,欢迎吐槽!
https://github.com/q7322068/rest-base,已用于多个正式项目,当前可能因为版本问题不是很完善,后续持续优化,希望你能有所收获!