system.getlogger 仅适用于不引入第三方依赖且日志需求极简的场景,如模块化系统内部调试;它不是 log4j2 或 slf4j 的替代品,也不支持运行时输出配置,底层绑定由启动时 loggerfinder 决定。

System.getLogger 用不用得上?
绝大多数 Java 应用——尤其是还在用 Log4j2、SLF4J + Logback 的项目——完全没必要迁移到 System.getLogger。它不是替代方案,而是 JDK 自带的轻量级门面,定位接近 java.util.logging.Logger,但更抽象、更“只读”。只有当你明确需要不引入第三方依赖、且日志需求极简(比如工具类、启动诊断、模块化系统内部调试),才值得考虑。
为什么 getLogWriter() 不生效?
System.getLogger 返回的是 Logger 实例,但它的行为完全由 JVM 启动时绑定的 System.LoggerFinder 决定。默认实现(jdk.internal.logger.DefaultLoggerFinder)根本不支持运行时替换底层输出——调用 setLogWriter 或类似方法无效,也不会报错,只是静默忽略。
- 真正生效的方式只有:启动时通过
--add-opens java.base/jdk.internal.logger=ALL-UNNAMED+ 自定义LoggerFinder子类,并用-Djdk.logger.finder=your.CustomFinder指定 - 普通应用无法通过配置文件或
ServiceLoader替换(JDK 9–17 中该机制未公开暴露) - 试图在 Spring Boot 或 Jakarta EE 环境里“接管”
System.getLogger输出,基本会失败
和 JUL(java.util.logging)的关系到底是什么?
它不是 JUL 的升级版,也不是封装层;它是并行存在的另一套抽象。JUL 的 Logger 是具体实现类,而 System.getLogger 返回的是接口 System.Logger,JDK 默认把它桥接到 JUL,但这个桥接是单向、不可配置的。
- 调用
System.getLogger("com.example")实际拿到的是一个包装了 JULjava.util.logging.Logger的适配器 - 所以 JUL 的
logging.properties依然控制它的输出格式和级别,但System.Logger接口本身不暴露setLevel、addHandler等方法 - 如果 JUL 被禁用(如
-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager),System.getLogger可能退化为丢弃所有日志,且无提示
什么时候真该用?举个实际例子
模块化(JPMS)环境下的跨模块轻量调试最贴近它的设计意图。比如你写了一个 java.base 之外的平台服务模块,想记录初始化状态,又不想强制依赖 SLF4J ——这时可以用:
立即学习“Java免费学习笔记(深入)”;
ModuleLayer.Controller controller = ModuleLayer.boot().controller();
controller.addModules(Set.of(YourModule.class));
// 在模块静态初始化块中
System.getLogger("YourModule").log(System.Logger.Level.DEBUG, "booted");
但要注意:System.Logger.Level 和 JUL 的 Level 枚举值不一一对应(例如没有 TRACE),且 log() 方法重载少,不支持 lazy lambda 形参(JDK 17 才加 log(Level, Supplier))。
真正容易被忽略的是:它的 isLoggable 判断开销比你想象中高——每次调用都会触发一次 LoggerFinder.getLogger 查找+适配器创建,高频日志场景下可能成为瓶颈。










