为什么不推荐使用 java.util.logging?
java.util.logging(JUL)提供 JDK 内置日志能力;需要更丰富的滚动、异步和上下文字段时,可选择 Logback 或 Log4j2 并通过 SLF4J 门面编程。本文对比能力与桥接注意事项。
一句话结论:JUL 不算"坏",是否更合适取决于配置、滚动、异步和集成需求,不能一概判断性能;一种常见做法是基于 SLF4J 门面编程,底层绑定 Logback(或 Log4j2),同时用 jul-to-slf4j 把依赖库里残留的 JUL 输出桥接过来统一管理。
JUL 的主要短板
1. 配置繁琐且不直观
JUL 用 properties 文件配置,Handler/Formatter 概念绕,支持编程配置和运行时级别调整;复杂规则的表达方式与 Logback/Log4j2 不同,不能把 Groovy 当作当前 Logback 内置配置支持。
2. 功能有限
缺少现代日志框架的标配能力:灵活的滚动策略(按时间+大小+压缩)、异步 Appender、MDC 的完整支持、条件化配置等。
3. 性能一般
同步输出、格式化与锁开销可能影响吞吐;Log4j2 异步 Logger 和 Logback AsyncAppender 可将工作移到后台,但需考虑队列满与退出行为,应按实际负载测试,不能断言总是更快。
4. 生态与社区薄弱
若项目已使用 SLF4J 与第三方后端,统一配置通常更方便;是否缺少集成应按具体目标与扩展核对,JUL 本身仍是 JDK 支持的日志系统。
推荐架构
业务代码 → SLF4J API → Logback(或 Log4j2)
依赖库的 JUL 输出 → jul-to-slf4j 桥接 → 同一套配置
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Service {
private static final Logger log = LoggerFactory.getLogger(Service.class);
public void run() {
log.info("处理订单 orderId={}", 1001);
}
}
门面编程的好处:换实现只改依赖不改代码。
桥接完成后,分别从老依赖的 JUL 和应用的 SLF4J 写一条测试日志,确认它们都进入同一输出文件且没有重复。观测云 DataKit 文件采集读取该文件后,再验证 logger 名、级别与异常堆栈,避免桥接成功却在解析时丢失来源。
常见问题(FAQ)
Q:老项目全是 JUL,要重写吗?
A:不必。引入 jul-to-slf4j 后还需安装 SLF4JBridgeHandler,并按应用权限处理旧 Handler 防止重复;JUL 级别过滤仍有效。不要同时绑定回 JUL 的 slf4j-jdk14,否则形成环路。原 JUL 调用可保留。
Q:Spring Boot 默认用什么?
A:默认 Logback + SLF4J,开箱即用;这也侧面说明了社区的选择。
Q:JUL 有什么适合的场景吗?
A:零依赖的小工具/库,不想引入任何第三方包时可以用——这正是它存在于 JDK 里的意义。