1. Java异常机制
1.1 使用异常、日志为系统保驾护航
- 异常应当描述导致当前异常发生的原因
- 根据异常栈快速定位到异常发生的位置
- 结合异常描述和异常栈解决异常
1.2 Java异常处理流程
1.3 Java异常处理机制
try代码块中可能抛出多种异常,该怎么捕获?
1. 如果处理流程一样,捕获公共父类的异常
2. 如果处理流程不一样,多catch捕获异常
1.4 Java异常体系
2. 异常处理设计与实践
2.1 异常抛出与捕获原则
- 非必要不使用异常
- 使用描述性消息抛出异常
- 力所能及的异常一定要处理
- 异常忽略要有理有据
2.2 Java异常体系之try...catch...finally流程解析
不要在finally中使用return
2.3 Java异常之try with resource流程解析
使用时,resource中的所有资源都需要显式的定义,才能都被调用关闭方法。
当try中发生异常,调用close()方法,当调用close()方法发生异常,捕获的是close的异常,try的异常会被吞并。打印异常时是需要注意。
2.4 特殊NPE场景及其处理对策
2.4.1 级联调用时易产生NPE
使用Optional优雅的解决NPE
2.4.2 foreach遍历集合的异常
- 不要在foreach循环里进行元素的remove、add操作
- foreach循环会自动跳过遍历空集合,如果对于有null值的集合,碰到null时需注意NPE
foreach或者for循环中抛出异常有什么影响?
1. 后面的循环不会执行
2. 前面已经处理的数据,不会保存,造成资源浪费
3. 日志
3.1 日志的功能
- 监控告警
- 记录行为轨迹
- 快速定位问题
3.2 日志时效规约
- 当天日志命名,以“应用名.log”
- 过往日志命名,以{logname}.log.{yyyy-MM-dd}命名
- 日志文件至少保存15天,以便排查,以周为频次发生的异常
- 敏感操作信息联机存储6个月,网络安全相关法律规定
3.3 日志输出规约
对于敏感信息联机存储6个月的日志,使用warn级别
3.4 日志记录规约
- 系统应依赖使用日志框架(SLF4J、JCL)的API而不是具体日志库中的
- 在日志输出时,字符串变量之间的拼接使用占位符的方式
- 日志打印时禁止直接用JSON工具将对象转换成String
- 尽量用英文来描述日志错误信息
老系统中的log4j日志实现库桥接至slf4j,使用slf4j门面(默认实现是logback)
使用JCL的项目改造成使用SLF4J(log4j日志库实现)
使用spring-boot,默认是logback,换log4j
3.5 logback框架使用之核心配置对象及属性分析
3.6 日志输出规约
- 日志级别开关判断
- 异常日志信息要完整,案发现场信息、异常堆栈信息
- 避免重复打印日志, 设置additivity=false
3.7 扩展日志规约
- 扩展日志单独存储(打点、临时监控、访问日志等)
- 错误日志单独存储(业务日志与错误日志分开)
4. 错误码规约
4.1 错误码的功用
- 系统与系统间的沟通
- 人与系统之间的沟通
- 人与人之间的沟通
4.2 错误码规约
- 定义时要有字母,也要有数字
- 要分级分类管理
- 不能直接输出给用户作为提示信息使用
- 不要与业务架构或者组织架构挂钩
- 使用者避免随意定义新的错误码
- 便于不同语音的开发者之间的协作
5. 异常处理与日志综合实践
5.1 在Controller层统一捕获异常
各层分布式部署在多台机器时,异常日志是否需要单独每层单独记录?
需要单独每层记录
5.2 全局异常处理组件的定义和使用
5.3 API层异常设计实践
- 严格约束条件判断(基本判断约束、实体属性约束)
- 客户端返回要友好(给客户端返回状态码及其对应的错误消息)
- 下层异常转译(将Service、Manager层异常转译成API层异常)
- 错误码文档要规范(系统状态码对应的异常或错误信息以及可能发生异常的原因,要整理成便于用户查阅的文档,同步给接口调用方)
5.4 Service层异常设计实践
- 严格约束条件判断(基本判断约束、实体属性约束、业务条件约束)
- 抛出指定类型的异常(抛出状态码或指定类型的异常)
- 转译DAO层异常(将DAO层的异常转译为Service层或者更高能够理解的异常)
5.5 DAO数据处理层异常日志实践
- 通用DaoException,使用继承自RuntimeException通用异常封装DAO层异常并向上抛出
- 框架层面有选择性的记录数据操作(每次操作的原始SQL语句及其执行时间)
5.6 使用MDC实现轻量级调用链路追踪
- 分布式链路追踪(将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示、比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等)
- 链路跟踪主要功能(故障快速定位、链路性能可视化、链路分析)
哪些数据可以放进MDC进行全局传递?
5.7 用有限的异常类处理业务中复杂多变的无限可能
- 通用ServiceException(定义继承自RuntimeException的通用ServciceException业务异常)
- 结合ErrorCode(结合与业务关联的ErrorCode实现复杂多变的业务异常需求)
5.8 降低系统的维护难度与过度设计、冗余的手段
一个系统通常要包含哪些通用的模块?