Day3-T31项目 异常处理与日志
2021-10-30
按道理来说应该是在10月30号完成第三天的笔记,但是因为个人原因,要去学校办理实习的相关证书和表格耽误了,拖到现在补交。嘿嘿~
Java异常机制
使用异常、日志为系统保驾护航
道路千万条,安全第一条。日志不规范,排查两行泪
- 异常应当描述导致当前异常发生的原因
- 根据异常栈快速定位到异常发生的位置
- 结合异常描述和异常栈解决异常
C语言的“异常”烦恼
此代码的异常处理问题说明:
- 代码可读性差
- 当返回值与异常值相近时,容易混淆
- 需要调用方来分析异常,增加多余的工作量
Java异常处理流程
Java异常处理机制
Java的异常体系
Throwable 涉及众人的 ”大异常“
- Error 机场地政,不可抗力
- Exception 不致命的,有可能恢复
- 非受检异常 Runtime Exception unchecked 异常
- 可预测异常:没带护照,只要提前检查即可
- 需捕捉异常:去机场路上车抛锚,虽然难预测,但必须处理,可以换别的交通工具
- 可透出异常:栓票机器故障,交由航空公司处理,不需要我们关心
- 受检异常 checked 异常
- 引起注意型:航班延误,我们无能为力
- 坦然处理型:堵车,我们可以改变路线,或者提前出发
- 非受检异常 Runtime Exception unchecked 异常
异常处理
异常抛出与捕获原则
- 非必要不使用异常
- 使用描述性消息抛出异常
- 力所能及的异常一定要处理
- 异常忽略要有理有据
Java异常体系之try…catch…finally流程解析
JDK7 资源关闭之try with resource流程解析
特殊异常NPE场景及其处理对策
级联调用时易产生 NPE
特殊NPE场景及其处理对策
使用 Optional 防止 NPE
使用 JDK8 的 Optional 类可以防止连续属性调用出现的 NPE 问题
- 实例化 Optional
- Potional.ofNullable(obj)
- 使用 orElse() 方法解决 NPE 问题
- orElse() 的作用是设置默认值,当发生 NPE 时,返回指定的默认值
- 使用 ifPresent() 方法解决 NPE 问题
- ifPresent(Consumer<? super T> consumer) 就是在 value 值不为空时,做一些操作
- 对象非空判断性能高
- 当总循环次数 <10000时,使用Optional 与普通的嵌套null非空检测查询稳定在30ms;
- 当总循环次数 >10000&<10000000时,Optional 比普通嵌套null非空检测查询性能查询10-20倍,Optional 消耗时间稳定在35-65ms之间;
- 当总循环次数 >10000000时,性能差距呈指数上升。
foreach遍历集合的异常
- 不要在foreach循环里进行元素的remove/add操作
- foreach循环会自动跳过遍历空集合,如果对于有null值的集合,碰到null时需要注意NPE。
日志规约
日志的功能
日志时效规约
日志记录规约
-
系统应依赖使用日志框架(SLPF4J、JCL)的API而不是具体日志库中的
-
在日志输出时,字符串变量之间的凭借使用占位符的方式
-
日志打印时禁止直接用 JSON 工具将对象转换成 String
-
尽量使用英文来描述日志错误信息
logback 框架使用核心配置对象及属性分析
logback日志框架使用配置文件解析
根节点 -configuration 及其通用属性的配置示例
Appender节点配置示例
logback日志框架使用关键类图分析
异步Appenter配置示例
logback日志记录线程模型分析
扩展日志规约
异常错误日志实时通知
将错误异常日志发送至邮箱与企业微信
整合Sentry将错误异常日志发送至企业钉钉消息
日志输出规约
-
日志级别开关判断
- 对于 trace/debug/info级别的日志输出,必须进行日志级别的开关判断
-
异常日志信息要完善
- 案发现场信息
- 异常堆栈信息
-
避免重复打印日志
- 重复打印日志,浪费磁盘空间,务必在日志配置文件中设置 additivty=false
扩展日志的设计与规约
-
扩展日志大百度存储
- 应用中的扩展日志(如打点、临时监控、访问日志等)单独存储
-
错误日志单独存储
- 业务日志与错误日志分开存储
错误码规约
错误码的作用
- 系统与系统减的沟通
- 人与人之间的沟通
- 人与系统之间的沟通
错误码规约
- 定义时要有字母也要有数字
- 要分级分类管理
- 不能直接输出给用户作为提示信息使用
- 不要与业务架构或组织架构挂钩
- 使用者避免随意定义新的错误码
- 便于不同语言的开发者之间协作
异常与日志综合实践
在Controller层统一捕获异常
全局异常处理组件GiobaiExceptionHandler
API层异常设计实践
-
严格约束条件判断
- API层要严格校验保证进入系统的数据是合法的
- 基本判断约束(null值等基本判断)
- 实体属性约束(满足JSR 303 基础判断)
- API层要严格校验保证进入系统的数据是合法的
-
客户端返回要“友好”
- API层异常要给客户端返回状态码及其对应的错误消息
-
下层异常转译
- 将Service层、Manager层异常转译成API层异常
-
错误码文档规范
- 系统状态码对应的异常或错误信息以及可能要发生异常的原因,要整理成便于用户查阅的文档,同步给接口调用方
Service层异常设计实践
-
严格约束条件判断
- Service层严格约束条件判断避免脏数据
- 基本判断约束(null值等基本判断)
- 实体属性约束(满足JSR 303 基础判断)
- 业务条件约束(需求提出的不同的业务约束)
- Service层严格约束条件判断避免脏数据
-
抛出指定类型的异常
- Service层抛出带状态码或者指定类型的异常
-
转译DAO层异常
- 将DAO层的异常转译为Service层或者更高层能够理解的异常
DAO数据处理层异常、日志实践
-
通用 DaoException
- 使用继承自Runtime Exception的通用DaoException封装DAO层异常并向上抛出
-
框架层面有选择性的记录数据操作
- 在DAO层(框架层面)有选择地记录数据操作的有效性息,比如:每次操作的原始SQL语句及其执行时间
使用MDC实现轻量级调用链路追踪
分布式链路追踪
将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等
链路跟踪主要功能
- 故障快速定位
- 链路性能可视化
- 链路分析
用有限的异常类处理业务中复杂多变的无限可能
-
通用ServiceException
- 定义继承自RuntimeException的通用ServiceException业务异常
-
结合ErrorCode
- 结合与业务关联的ErrorCode实现复杂多变的业务异常需求
降低系统的维护难度与过度设计、冗余的手段
系统维护:代码的维护系统运营维护