最推荐的方式是父类声明 protected static final logger log = loggerfactory.getlogger(parentclass.class),子类直接使用;若需显示子类真实类名,则改用构造器注入 class 参数初始化非 static final log。

在 Java 继承体系中,子类复用父类的日志组件,核心是让日志对象(如 SLF4J 的 Logger)能被子类安全、正确地访问,同时避免重复创建或静态污染。最推荐的方式是将 Logger 声明为 protected 且 static final,并在父类中初始化。
用 protected static final Logger 复用
这是最简洁、线程安全、符合 SLF4J 最佳实践的做法:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 父类中定义:
protected static final Logger log = LoggerFactory.getLogger(ParentClass.class); - 子类直接使用
log.info("..."),无需重新声明或初始化 - 注意:必须用
ParentClass.class(而非this.getClass()),否则日志输出的类名永远是父类,丢失子类上下文
如果需要子类显示真实类名(推荐进阶方案)
当希望日志中显示实际调用类(比如 ChildService 而非 BaseService),不建议在父类用 this.getClass()(因 static 上下文中不可用),而是改用模板方法 + 构造器注入:
- 父类定义
protected final Logger log;(非 static) - 父类构造器接收
Class> clazz,内部初始化:this.log = LoggerFactory.getLogger(clazz); - 子类构造器显式传入自身 class:
super(ChildService.class); - 这样每个子类实例拥有对应类名的日志器,且复用父类日志能力
避免常见错误
- ❌ 不要用
private static Logger—— 子类无法访问 - ❌ 不要在子类里写
private static final Logger log = LoggerFactory.getLogger(ChildService.class)—— 破坏复用,且和父类日志逻辑割裂 - ❌ 不要用
LoggerFactory.getLogger(this.getClass())在 static 字段中 —— 编译不通过 - ❌ 不要每次方法都调用
LoggerFactory.getLogger(...)—— 性能损耗,且 SLF4J 不推荐频繁获取 logger 实例
补充:配合 Lombok 可更简洁
若项目使用 Lombok,可直接在父类加 @Slf4j 注解(它会生成 protected static final Logger log),但需注意其默认用当前类 class —— 此时父类加 @Slf4j,子类继承后仍输出父类名。如需真实类名,Lombok 不适用,应回归手动构造器方案。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










