1. 简介

JUL(Java Util Logging)是 Java 内置的日志框架。虽然简单易用,但缺乏现代日志框架的灵活性和高级特性。因此许多项目会选择其他日志方案。

但在模块化软件和第三方依赖盛行的今天,应用中某些组件可能仍使用 JUL,即使我们更倾向于其他日志框架。这导致日志配置变得复杂。

本文将介绍如何利用 SLF4J 的 JUL 到 SLF4J 桥接器解决这个问题。

2. 依赖配置

首先在项目中添加 SLF4J 相关依赖。对于 Maven 项目,在 pom.xml 中加入以下依赖:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.16</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>2.0.16</version>
</dependency>

jul-to-slf4j 包含一个 java.util.logging (JUL) 处理器——SLF4JBridgeHandler,它负责将所有 JUL 日志记录路由到 SLF4J API。

⚠️ 注意:应用还需指定 SLF4J 的具体实现。本文以 slf4j-simple 为例:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.16</version>
</dependency>

3. 默认 JUL 日志输出

未配置桥接器时,若第三方库使用 JUL 记录日志,输出将采用 JUL 默认格式。例如:

import java.util.logging.Logger;

public class BusinessLogic {

    static void julLog(Logger julLogger) {
        julLogger.info("This is a JUL info log message!");
        julLogger.warning("This is a JUL warning log message!");
    }
}

运行 julLog() 方法将输出类似内容:

Jan 19, 2025 11:43:41 PM com.baeldung.BusinessLogic julLog INFO: This is a JUL info log message!
Jan 19, 2025 11:43:41 PM com.baeldung.BusinessLogic julLog WARNING: This is a JUL warning log message!

4. 配置桥接器

可通过编程方式或 logging.properties 文件配置桥接器。下面分别介绍。

4.1 编程式配置

在应用主类中编程式安装桥接器。此方法简单直接,确保在应用初始化阶段完成安装:

import org.slf4j.bridge.SLF4JBridgeHandler;
import java.util.logging.Logger;

public static void main(String[] args) {
    // 移除现有处理器
    SLF4JBridgeHandler.removeHandlersForRootLogger();

    // 安装 SLF4J 桥接器
    SLF4JBridgeHandler.install();

    // 测试桥接器安装后的输出
    BusinessLogic.julLog(julLogger);

    BusinessLogic.slf4jLog(logger);
}

代码逻辑:

  1. 移除所有 JUL 处理器避免重复日志
  2. 安装 SLF4J 桥接器,将 JUL 日志重定向到 SLF4J

4.2 通过 logging.properties 配置

也可使用 JUL 的 logging.properties 文件声明式配置。此方法适合无法修改代码或添加编程配置的场景。

src/main/resources/logging.properties 中添加:

handlers = org.slf4j.bridge.SLF4JBridgeHandler
.level = INFO

配置说明:

  • handlers 指定 SLF4JBridgeHandler 处理 JUL 根日志
  • .level 设置默认日志级别为 INFO(仅记录该级别及以上日志)

JUL 默认使用 JAVA_HOME/conf/logging.properties。需通过 JVM 参数指定自定义配置文件路径:

-Djava.util.logging.config.file=/path/to/logging.properties

❌ 缺点:此方式需管理 JUL 内部配置。编程式配置则可完全通过 SLF4J API 实现。

5. 测试日志配置

配置完成后,通过测试验证桥接器是否正常工作。

5.1 通过 JUL 记录日志

即使第三方库使用 JUL,日志消息现在也会通过 SLF4J 路由:

import java.util.logging.Logger;

public class BusinessLogic {
    static void julLog(Logger julLogger) {
        julLogger.info("This is a JUL info log message!");
        julLogger.warning("This is a JUL warning log message!");
    }
}

julLog() 输出将变为 SLF4J 格式(以 slf4j-simple 为例):

[main] INFO com.baeldung.JULAppWithProgrammaticSLF4J - This is a JUL info log message!
[main] WARN com.baeldung.JULAppWithProgrammaticSLF4J - This is a JUL warning log message!

5.2 直接通过 SLF4J 记录日志

虽然桥接器支持 JUL,但最佳实践是直接声明 SLF4J 日志器:

public class BusinessLogic {
    static void slf4jLog(org.slf4j.Logger logger) {
        logger.info("This is an SLF4J info log message!");
        logger.error("This is an SLF4J error log message!");
    }
}

通过同时测试 JUL 和 SLF4J 日志,可验证集成是否成功。

6. 总结

✅ 核心要点:

  1. JUL 到 SLF4J 桥接器解决了混合日志框架的统一管理问题
  2. 支持编程式和声明式两种配置方式
  3. 编程式配置更灵活,声明式配置适合特殊场景
  4. 测试时需同时验证 JUL 和 SLF4J 日志输出

通过桥接器,我们既保留了第三方库的 JUL 日志,又统一了日志管理,避免了多框架日志混乱的踩坑问题。