系统异常设计的出发点
- 良好的信息展示,开发运维人员能快速定位问题
- 响应外部调用异常时,应能明确指明是内部异常还是调用条件不满足导致
- 响应用户操作异常时,能友好的提示用户
如何做到上述三点
- 对异常进行分类
- 内部异常
- 资源环境导致
- 第三方服务错误响应
- 第三方响应结果错误
- 外部传入参数非法
- 错误的编码逻辑
- 错误的配置
- 异常的业务数据(业务数据缺失导致)
- 业务异常
- 用户操作错误
- 业务条件不满足
- 内部异常
2.在系统中正确的捕获这类 异常,并抛出
-
- 方法入参进行合法性验证
- 对系统外部提供的接口,是必须进行参数验证的(必须)
- 系统内部对外外层提供的接口,进行验证
- public方法 进行参数验证
- private方法没必须进行参数验证
- 第三方响应结果合法性验证
- 获取第三方结果后,根据你们的约定进行验证
- 业务处理前,对业务业务前置条件进行验证
- 业务处理前,验证业务条件(验证余额,验证这个账户有没有被公安锁定)
- 要考虑性能成本(验证身份证号码是不是存在)
- 业务处理 后,对处理结果进行验证
- 验证对方账户是不是到账了,转出账户是不是成功扣款
- 对于可能出现异常 的代码进行try catch捕获4
- 尝试恢复处理
- 直接抛出
- 转换后抛出
- 方法入参进行合法性验证
3.最后在系统出口统一拦截处理
-
- WEB Response
- 内部异常
- 引导至异常提示页
- 业务异常
- 返回对应提示消息至前端
- 未知异常
- 尝试进行识别,转换成编码异常
- 内部异常
- HTTP API接口响应
- 内部异常:返回接口不可用
- 参数错误:基于API文档中的异常列表进行响应返回。表名参数非法,需要调用方加强参数合法性验证
- 业务错误:基于接口约定返回对应code与消息
- RPC Service响应
- 内部异常:返回服务不可用消息
- 参数错误:基于接口文档进行响应,直接返回异常堆栈
- 业务错误 : 直接返回异常堆栈
- checkedException
- WEB Response
异常定义技巧
基于分包表示异常的分类,不建议使用继承
创建异常类 定义业务异常,不建议使用Code来定义
使用枚举来表示业务异常的几种结果,不建议使用code
例如:TradeContext
public class TradeContext{ //参数验证断言 //异常转换 //异常信息加工:如国际化public static void assertIsNotNull(Object param,String message){ if(param==null){ throw new ParamException(message);}}public static void transformExcption(Exception exception){}}public UserInfo getUser(Integer id){ TradeContext.assertIsNotNull(id,"id不能为空"); return mapper.selectBYPrimaryId(id);}
常见的错误异常处理
1、直接忽略
try { new String(source.getBytes("UTF-8"), "GBK"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } 正确的处理方式try { new String(source.getBytes("UTF-8"), "GBK"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("环境不支持UTF-8",e) }
2、用一个统一异常替代所有业务异常
public class ServiceException extends RuntimeException { public ServiceException(Exception e) { super(e); } public ServiceException(String message) { super(message); }
`错误:`
- 必须明确定义业务异常
- 尽可能申明为checkedException
- 要带上具体业务数据
`正确方式`: 定义明确的业务异