T31-异常处理与日志学习笔记

640 阅读5分钟

1. Java异常机制

1.1 使用异常、日志为系统保驾护航

  1. 异常应当描述导致当前异常发生的原因
  2. 根据异常栈快速定位到异常发生的位置
  3. 结合异常描述和异常栈解决异常

1.2 Java异常处理流程

image.png

1.3 Java异常处理机制

image.png

try代码块中可能抛出多种异常,该怎么捕获?
1. 如果处理流程一样,捕获公共父类的异常
2. 如果处理流程不一样,多catch捕获异常

1.4 Java异常体系

image.png

2. 异常处理设计与实践

2.1 异常抛出与捕获原则

  1. 非必要不使用异常
  2. 使用描述性消息抛出异常
  3. 力所能及的异常一定要处理
  4. 异常忽略要有理有据

2.2 Java异常体系之try...catch...finally流程解析

不要在finally中使用return

image.png

2.3 Java异常之try with resource流程解析

image.png

image.png 使用时,resource中的所有资源都需要显式的定义,才能都被调用关闭方法。 当try中发生异常,调用close()方法,当调用close()方法发生异常,捕获的是close的异常,try的异常会被吞并。打印异常时是需要注意。

2.4 特殊NPE场景及其处理对策

2.4.1 级联调用时易产生NPE

image.png 使用Optional优雅的解决NPE

2.4.2 foreach遍历集合的异常

  1. 不要在foreach循环里进行元素的remove、add操作
  2. foreach循环会自动跳过遍历空集合,如果对于有null值的集合,碰到null时需注意NPE
foreach或者for循环中抛出异常有什么影响?
1. 后面的循环不会执行
2. 前面已经处理的数据,不会保存,造成资源浪费

3. 日志

3.1 日志的功能

image.png

  1. 监控告警
  2. 记录行为轨迹
  3. 快速定位问题

3.2 日志时效规约

  1. 当天日志命名,以“应用名.log”
  2. 过往日志命名,以{logname}.log.{yyyy-MM-dd}命名
  3. 日志文件至少保存15天,以便排查,以周为频次发生的异常
  4. 敏感操作信息联机存储6个月,网络安全相关法律规定

3.3 日志输出规约

对于敏感信息联机存储6个月的日志,使用warn级别

3.4 日志记录规约

  1. 系统应依赖使用日志框架(SLF4J、JCL)的API而不是具体日志库中的
  2. 在日志输出时,字符串变量之间的拼接使用占位符的方式
  3. 日志打印时禁止直接用JSON工具将对象转换成String
  4. 尽量用英文来描述日志错误信息

image.png

老系统中的log4j日志实现库桥接至slf4j,使用slf4j门面(默认实现是logback) image.png

使用JCL的项目改造成使用SLF4J(log4j日志库实现) image.png

image.png

使用spring-boot,默认是logback,换log4j image.png

3.5 logback框架使用之核心配置对象及属性分析

image.png

3.6 日志输出规约

  1. 日志级别开关判断
  2. 异常日志信息要完整,案发现场信息、异常堆栈信息
  3. 避免重复打印日志, 设置additivity=false

image.png

3.7 扩展日志规约

  1. 扩展日志单独存储(打点、临时监控、访问日志等)
  2. 错误日志单独存储(业务日志与错误日志分开)

4. 错误码规约

4.1 错误码的功用

  1. 系统与系统间的沟通
  2. 人与系统之间的沟通
  3. 人与人之间的沟通

4.2 错误码规约

  1. 定义时要有字母,也要有数字
  2. 要分级分类管理
  3. 不能直接输出给用户作为提示信息使用
  4. 不要与业务架构或者组织架构挂钩
  5. 使用者避免随意定义新的错误码
  6. 便于不同语音的开发者之间的协作

image.png

5. 异常处理与日志综合实践

5.1 在Controller层统一捕获异常

image.png

各层分布式部署在多台机器时,异常日志是否需要单独每层单独记录?
需要单独每层记录

5.2 全局异常处理组件的定义和使用

image.png

5.3 API层异常设计实践

  1. 严格约束条件判断(基本判断约束、实体属性约束)
  2. 客户端返回要友好(给客户端返回状态码及其对应的错误消息)
  3. 下层异常转译(将Service、Manager层异常转译成API层异常)
  4. 错误码文档要规范(系统状态码对应的异常或错误信息以及可能发生异常的原因,要整理成便于用户查阅的文档,同步给接口调用方)

5.4 Service层异常设计实践

  1. 严格约束条件判断(基本判断约束、实体属性约束、业务条件约束)
  2. 抛出指定类型的异常(抛出状态码或指定类型的异常)
  3. 转译DAO层异常(将DAO层的异常转译为Service层或者更高能够理解的异常)

5.5 DAO数据处理层异常日志实践

  1. 通用DaoException,使用继承自RuntimeException通用异常封装DAO层异常并向上抛出
  2. 框架层面有选择性的记录数据操作(每次操作的原始SQL语句及其执行时间)

5.6 使用MDC实现轻量级调用链路追踪

  1. 分布式链路追踪(将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示、比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等)
  2. 链路跟踪主要功能(故障快速定位、链路性能可视化、链路分析)

image.png

image.png

哪些数据可以放进MDC进行全局传递?

5.7 用有限的异常类处理业务中复杂多变的无限可能

  1. 通用ServiceException(定义继承自RuntimeException的通用ServciceException业务异常)
  2. 结合ErrorCode(结合与业务关联的ErrorCode实现复杂多变的业务异常需求)

5.8 降低系统的维护难度与过度设计、冗余的手段

image.png

一个系统通常要包含哪些通用的模块?

image.png