抽象类统一日志契约并封装公共逻辑,子类仅实现具体框架的doLog()方法;业务层调用final模板方法,通过SPI加载适配器,配合MDC、级别映射等机制保障日志标准一致性。

在日志门面抽象层中,用抽象类定义统一日志输出标准的核心思路是:**把日志行为的契约(如方法签名、日志级别语义、上下文规范)收拢到抽象类,而将具体日志实现(如 SLF4J、Log4j2、JUL)的调用逻辑交给子类完成**。这样既保证了上层业务代码调用方式一致,又解耦了底层日志框架。
抽象日志门面类定义统一接口
抽象类不直接持有 Logger 实例,而是声明抽象方法,强制子类提供日志器获取和输出能力:
-
定义抽象方法:如
protected abstract void doLog(Level level, String msg, Object... args),统一日志入口; - 封装公共逻辑:在非抽象方法中做格式预处理、MDC 上下文注入、敏感字段脱敏、调用栈裁剪等,所有子类自动复用;
-
约定日志结构:通过受保护的模板方法(如
formatLogMessage())约束日志前缀、TraceID、服务名、线程名等字段顺序与格式。
子类负责绑定具体日志框架
每个子类对应一种日志实现,只关心“怎么把标准日志写出去”,不改变语义:
-
Slf4jLoggerAdapter extends AbstractLogger:内部持org.slf4j.Logger,doLog()中调用slf4jLogger.debug()/info()等,并适配参数占位符; -
Log4j2LoggerAdapter extends AbstractLogger:使用org.apache.logging.log4j.Logger,注意 Log4j2 的 lazy-evaluation 特性(如logger.debug("msg: {}", () -> heavyCompute()))可由子类决定是否支持; - 子类还可覆盖
isDebugEnabled()等开关方法,对接底层框架的启用判断逻辑。
业务层面向抽象日志类编程
业务代码不依赖 slf4j-api 或 log4j-api,而是依赖你自己的抽象日志类:
立即学习“Java免费学习笔记(深入)”;
- 注入或获取
AbstractLogger实例(可通过工厂或 SPI 加载具体子类); - 调用
logger.info("User {} logged in", userId)—— 这个info()是抽象类提供的模板方法,内部转成doLog(INFO, ...); - 日志内容、结构、上下文均由抽象层统一控制,子类只负责“搬运”和“落地”,不参与业务语义设计。
配套机制增强一致性
仅靠抽象类还不够,需配合以下设计保障标准落地:
-
禁止子类重写公共日志方法:将
info()、error()等设为final,只允许重写doLog(); -
提供默认上下文工具:抽象类内置
withMdc(String key, String value)方法,自动绑定到 MDC,子类无需重复实现上下文传递; -
日志级别映射表:抽象类内建
Level枚举(DEBUG/WARN/ERROR),子类按需映射到底层框架的对应级别,避免语义错位(如 JUL 的SEVERE对应 ERROR,而非 FATAL)。


















