第九课实战版:异常与日志体系 —— 后端稳定性的第一道防线

第9课的目标,从来不是教你"写几个异常类"。

而是:在你的后端工程中,亲手搭建一套

👉 可扩展、可定位、可治理的稳定性底座。

从这一课开始,你写的不再只是功能代码,

而是在搭一套系统工程能力

如果用 Android 来类比,这一课本质上是在后端项目中建立:

  • BaseResponse
  • 全局异常处理
  • 拦截器 / Filter
  • 统一日志与 requestId

也就是:后端的 base / core 模块(Infrastructure)

一、第9课在整套 24 课体系中的真实位置

在前 8 课,你已经完成了:

  • 分层架构(interfaces / application / domain / infrastructure)
  • ORM、事务、Service 编排

但到目前为止,你的系统还不具备"工程稳定性"

👉 第9课的角色是:
给整个系统安装"神经系统 + 黑匣子 + 保险丝"。

它直接支撑后续:

  • 第10课 Controller 规范
  • 第11课 接口质量工程
  • 第12课 登录与身份系统

所以,第9课不在业务层,而在:

Infrastructure ------ 基础设施层 / 工程底座

二、Infrastructure 是什么?(Android 视角最容易懂)

Infrastructure = 业务无关 + 全局复用 + 系统级能力

就像 Android 里的 base 模块:

  • BaseActivity / BaseResponse
  • 网络拦截器
  • 全局异常
  • 日志、埋点、trace

在后端里,它对应的就是:

  • 统一返回体 Result
  • 错误码体系 ErrorCode
  • 业务异常 BizException
  • 全局异常处理器
  • requestId / traceId
  • 日志规范 / Filter / AOP

👉 它不解决"业务",

👉 它决定"系统怎么活"。

三、第9课实战目标(必须形成的工程闭环)

完成这一课,你的工程中必须出现:

  • ✅ infrastructure/common 基础模块
  • ✅ 统一异常体系(业务失败 + 系统事故)
  • ✅ 统一返回体
  • ✅ requestId 全链路
  • ✅ 日志分层规范
  • ✅ 线上问题可反向定位能力

这是后续所有系统能力的地基。

四、工程落位(基础设施层包结构)

复制代码
infrastructure
└── common
    ├── result        // 统一返回体(BaseResponse)
    ├── error         // 错误码体系
    ├── exception     // BizException / GlobalHandler
    ├── web           // Filter / Interceptor
    ├── log           // 日志规范 / AOP(扩展)
    └── util

👉 这一整块,就是你项目的"base 模块"。

五、异常体系骨架(系统的失败模型)

1️⃣ 统一返回体 Result

java 复制代码
public class Result<T> {
    private boolean success;
    private String code;
    private String message;
    private T data;
    private String requestId;
}

👉 所有接口输出统一,所有失败工程化。

2️⃣ 错误码体系 ErrorCode

java 复制代码
public interface ErrorCode {
    String code();
    String message();
}
java 复制代码
public enum UserErrorCode implements ErrorCode {
    USER_NOT_FOUND("U_404", "用户不存在"),
    PHONE_EXISTS("U_409", "手机号已注册");
}
java 复制代码
public enum SystemErrorCode implements ErrorCode {
    SYSTEM_ERROR("SYS_500", "系统繁忙"),
    UNAUTHORIZED("SYS_401", "未登录"),
    FORBIDDEN("SYS_403", "无权限");
}

👉 错误不是字符串,是系统语义。

3️⃣ 业务异常 BizException

java 复制代码
public class BizException extends RuntimeException {
    private final String code;

    public BizException(ErrorCode errorCode) {
        super(errorCode.message());
        this.code = errorCode.code();
    }

    public String getCode() {
        return code;
    }
}

使用:

java 复制代码
if (!userExists) {
    throw new BizException(UserErrorCode.USER_NOT_FOUND);
}

👉 业务层只描述"失败",不处理失败。

4️⃣ 全局异常出口 GlobalExceptionHandler

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BizException.class)
    public Result<Void> handleBiz(BizException e) {
        log.warn("biz error: {}", e.getMessage());
        return Result.fail(e.getCode(), e.getMessage(), RequestId.get());
    }

    @ExceptionHandler(Exception.class)
    public Result<Void> handleSystem(Exception e) {
        log.error("system error", e);
        return Result.fail("SYS_500", "系统繁忙", RequestId.get());
    }
}

👉 所有异常,在这里结束。

六、日志体系骨架(系统的黑匣子)

1️⃣ requestId(每个请求的"案号")

java 复制代码
public class RequestIdFilter implements Filter {
    public void doFilter(...) {
        String requestId = UUID.randomUUID().toString();
        MDC.put("requestId", requestId);
        chain.doFilter(request, response);
        MDC.clear();
    }
}

logback:

java 复制代码
requestId=%X{requestId}

👉 所有日志自动带 requestId。

2️⃣ 日志分层原则

  • Controller:接口入口 / 参数 / 耗时
  • Application:业务流程 / 编排
  • Domain:关键业务决策
  • Infrastructure:IO / DB / MQ
  • ExceptionHandler:事故日志

错误日志必须能回答:

👉 谁 → 干了什么 → 为什么失败 → 关键数据

七、最小工程闭环示例

Controller:

java 复制代码
@PostMapping("/users")
public Result<UserDTO> register(@RequestBody RegisterReq req) {
    return Result.ok(service.register(req), RequestId.get());
}

Domain / Application:

java 复制代码
if (repo.exists(phone)) {
    throw new BizException(UserErrorCode.PHONE_EXISTS);
}

异常 → GlobalHandler → Result → requestId → 日志定位

👉 至此,第9课工程闭环成立。

八、第9课完成标准(极其重要)

当你满足下面 6 条,你这一课才算真正完成:

  • ✅ infrastructure/common 独立存在
  • ✅ 项目中几乎没有到处 try-catch
  • ✅ 所有业务失败统一 BizException
  • ✅ 所有未知失败统一 system error
  • ✅ 所有日志带 requestId
  • ✅ 报错可以反向还原一次请求

九、第9课对你能力层级的意义

从这一课开始,你已经不再是:

❌ 写接口的人

而是在做:

✅ 系统稳定机制设计

✅ 工程底座搭建

✅ 事故可治理能力

你已经站在架构能力起点了。

十、总结

真正稳定的系统,不是从不出错,

而是出错时,依然可控、可查、可修。

第9课搭的不是异常类,

是一套系统的"生命线"。

相关推荐
hssfscv2 小时前
Javaweb学习笔记——后端实战7 springAOP
笔记·后端·学习
钦拆大仁2 小时前
Java设计模式-状态模式
java·设计模式·状态模式
人道领域2 小时前
javaWeb从入门到进阶(SpringBoot基础案例2)
java·开发语言·mybatis
BHXDML2 小时前
数据结构:(二)逻辑之门——栈与队列
java·数据结构·算法
码农水水2 小时前
米哈游Java面试被问:Shenandoah GC的Brooks Pointer实现机制
java·开发语言·jvm·spring boot·redis·安全·面试
星辰_mya2 小时前
Netty
java·架构·io
九皇叔叔2 小时前
【06】SpringBoot3 MybatisPlus 修改(Mapper)
java·spring boot·mybatis·mybatisplus
如果'\'真能转义说2 小时前
Spring 概述
java·spring
cyforkk2 小时前
07、Java 基础硬核复习:面向对象编程(进阶)的核心逻辑与面试考点
java·开发语言·面试