Java - 日志体系_Apache Commons Logging(JCL)日志接口库

文章目录

  • [Apache Commons](#Apache Commons)
    • [Apache Commons Proper](#Apache Commons Proper)
    • [官网 Logging (Apache Commons Logging )](#官网 Logging (Apache Commons Logging ))
  • [1. 什么是JCL?](#1. 什么是JCL?)
  • [2. JCL的主要特点](#2. JCL的主要特点)
  • [3. JCL的核心组件](#3. JCL的核心组件)
  • [4. JCL的实现机制](#4. JCL的实现机制)
  • [5. SimpleLog 简介](#5. SimpleLog 简介)
  • [6. Code](#6. Code)
    • [Example 1 : 默认日志实现 (JCL 1.3.2版本)](#Example 1 : 默认日志实现 (JCL 1.3.2版本))
    • [Example 2 : JCL (1.2版本) + Log4J 【安全风险高,请勿使用】](#Example 2 : JCL (1.2版本) + Log4J 【安全风险高,请勿使用】)
    • [Example 3 : JCL 适配log4j2](#Example 3 : JCL 适配log4j2)
    • [Example 4 : JCL 桥接 logback](#Example 4 : JCL 桥接 logback)
  • [7. 使用场景与优点](#7. 使用场景与优点)
  • [8. 常见问题](#8. 常见问题)
  • [9. 动态绑定机制源码分析](#9. 动态绑定机制源码分析)
  • [10. 总结](#10. 总结)

Apache Commons

官网:Apache Commons

Apache Commons Proper

Commons Proper 致力于一个主要目标: 创建和维护可重用的 Java 组件。这 Commons Proper 是一个协作和共享的地方,其中 来自整个 Apache 社区的开发人员都可以 一起讨论由 Apache 项目共享的项目,以及 Apache 用户。

共享资源开发人员将努力确保他们的 组件对其他库的依赖性最小,因此 这些组件可以轻松部署。此外,共享资源 组件将尽可能保持其接口稳定,因此 Apache 用户(包括其他 Apache 项目)可以实现 这些组件。

组件 描述 最新 Maven 版本 发布版本 发布日期
BCEL 字节码工程库 - 分析、创建和操作 Java 类文件 6.10.0 6.10.0 2024-07-23
BeanUtils Java 反射和 introspection API 的易用封装 1.9.4 1.9.4 2019-08-13
BSF Bean 脚本框架 - 提供对脚本语言的接口,包括 JSR-223 3.1 3.1 2010-06-24
CLI 命令行参数解析器 1.9.0 1.9.0 2024-08-14
Codec 通用的编码/解码算法(例如音标、base64、URL) 1.17.1 1.17.1 2024-07-15
Collections 扩展或增强 Java 集合框架 4.5.0-M3 4.5.0-M3 2024-12-18
Compress 定义用于处理 tar、zip 和 bzip2 文件的 API 1.27.1 1.27.1 2024-08-20
Configuration 用于读取各种格式的配置/偏好文件 2.11.0 2.11.0 2024-06-10
Crypto 一个针对 AES-NI 优化的加密库,包装了 OpenSSL 或 JCE 算法实现 1.2.0 1.2.0 2023-01-23
CSV 处理逗号分隔值文件的组件 1.12.0 1.12.0 2024-09-25
Daemon 为 Unix 守护进程般的 Java 代码提供替代调用机制 1.3.4 1.3.4 2023-05-12
DBCP 数据库连接池服务 2.13.0 2.13.0 2024-12-02
DbUtils JDBC 辅助库 1.8.1 1.8.1 2023-09-14
Digester XML 到 Java 对象的映射工具 3.2 3.2 2011-12-13
Email 用于从 Java 发送电子邮件的库 2.0.0-M1 2.0.0-M1 2024-06-27
Exec 用于处理外部进程执行和环境管理的 API 1.4.0 1.4.0 2024-01-05
FileUpload 为您的 servlets 和 Web 应用提供文件上传功能 1.5 1.5 2023-12-27
FileUpload2 为您的 servlets 和 Web 应用提供文件上传功能(版本 2) 2.0.0-M1 2.0.0-M1 2023-07-19
Geometry 空间和坐标处理 1.0 1.0 2021-08-21
Imaging 一个纯 Java 图像库(之前称为 Sanselan) 1.0.0-alpha5 1.0.0-alpha5 2024-04-18
IO 一组 I/O 工具类 2.18.0 2.18.0 2024-11-19
JCI Java 编译器接口 1.1 1.1 2013-10-14
JCS Java 缓存系统 3.2.1 3.2.1 2024-05-27
Jelly 基于 XML 的脚本和处理引擎 1.0.1 1.0.1 2017-09-25
Jexl 扩展 JSTL 表达式语言的表达式语言 3.4.0 3.4.0 2024-06-05
JXPath 使用 XPath 语法操作 Java Beans 的工具集 1.3 1.3 2008-08-14
Lang 为 java.lang 类提供额外的功能 3.17.0 3.17.0 2024-08-29
Logging 包装了多种日志 API 实现 1.3.4 1.3.4 2024-08-19
Math 轻量级、自包含的数学和统计学组件 4.0-beta1 4.0-beta1 2022-12-20
Net 一组网络工具类和协议实现 3.11.1 3.11.1 2024-06-10
Numbers 数字类型(复数、四元数、分数)和工具(数组、组合数学等) 1.2 1.2 2024-08-12
Pool 通用对象池组件 2.12.0 2.12.0 2023-09-30
RDF RDF 1.1 的通用实现,可由 JVM 上的系统实现 0.5.0 0.5.0 2017-12-23
RNG 随机数生成器的实现 1.6 1.6 2024-07-15
SCXML SCXML 规范的实现,旨在创建和维护 Java SCXML 引擎 0.9 0.9 2008-12-01
Statistics 统计学工具 1.1 1.1 2024-08-20
Text Apache Commons Text 是一个专注于字符串操作的算法库 1.13.0 1.13.0 2024-12-13
Validator 用于在 XML 文件中定义验证器和验证规则的框架 1.9.0 1.9.0 2024-05-28
VFS 虚拟文件系统组件,用于将文件、FTP、SMB、ZIP 等视为一个逻辑文件系统 2.9.0 2.9.0 2021-07-21
Weaver 提供一种简单的方式来增强(织入)已编译的字节码 2.0 2.0 2018-09-07

官网 Logging (Apache Commons Logging )

https://commons.apache.org/proper/commons-logging/

组件 描述 最新 Maven 版本 发布版本 发布日期
Logging 包装了多种日志 API 实现 1.3.4 1.3.4 2024-08-19

1. 什么是JCL?

Apache Commons Logging(简称 JCL)是一个轻量级的日志接口库,提供了日志记录的抽象层。它允许开发人员编写独立于具体日志实现的代码,而具体的日志实现(如Log4j、SLF4J或java.util.logging)可以在运行时配置。这种设计简化了日志库的集成和切换。


2. JCL的主要特点

  • 灵活性:通过抽象层,可以自由选择日志实现。
  • 自动发现机制:运行时动态发现类路径中的可用日志实现。
  • 兼容性 :支持主流日志框架,如Log4j、SLF4J和java.util.logging
  • 简单易用 :只需依赖commons-logging.jar,无需复杂配置。

3. JCL的核心组件

  • Log 接口

    提供通用的日志记录方法(如debuginfowarnerrorfatal)。

    java 复制代码
    Log log = LogFactory.getLog(YourClass.class);
    log.info("信息日志");
    log.error("错误日志");
  • LogFactory 类

    用于创建Log接口的实例。LogFactory实现了日志系统的自动发现和绑定。


4. JCL的实现机制

JCL使用自动发现机制选择合适的日志实现:

  1. 首先检查类路径中是否存在Log4j,如果存在则使用Log4j (高版本的JCL已经移除了对log4j的支持)
  2. 如果找不到Log4j,JCL会检查java.util.logging并使用它。
  3. 如果前两个都不可用,则使用内置的SimpleLog作为默认实现。

可以通过配置文件commons-logging.properties显式指定日志实现。例如:

properties 复制代码
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

5. SimpleLog 简介

JCL内置的SimpleLog是一个轻量级实现,适用于没有复杂日志需求的小型项目。

它通过系统属性进行配置,例如:

  • org.apache.commons.logging.simplelog.defaultlog:设置默认日志级别。
  • org.apache.commons.logging.simplelog.showdatetime:是否显示日期时间。

6. Code

POM

java 复制代码
  <dependency>
   	 <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.3.2</version>
  </dependency>

Example 1 : 默认日志实现 (JCL 1.3.2版本)

java 复制代码
package com.artisan.jcl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class JavaCommonsLoggingTest {

    private static final Log log = LogFactory.getLog(JavaCommonsLoggingTest.class);

    public static void main(String[] args) {

        log.info("这是信息日志");
        log.warn("这是警告日志");
        log.error("这是错误日志");
    }
}

Example 2 : JCL (1.2版本) + Log4J 【安全风险高,请勿使用】

log4j1从2005年11月更新到2012年3月, 最新的依赖(May 26, 2012)

java 复制代码
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

2015年8月5日,项目管理委员会宣布Log4j 1.x已End Of Life 。建议用户使用Log4j 1升级到Apache Log4j 2

为了演示这种组合,我们将JCL降级到1.2版本

pom

xml 复制代码
   <!-- Jakarta Commons Logging -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- Log4j 核心依赖 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

log4j.properties

properties 复制代码
# 设置根日志记录器的日志级别为 DEBUG,并将其输出到控制台和文件
log4j.rootLogger=DEBUG, console, file

# 配置控制台输出
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# 可选:配置日志文件滚动
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=application.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# 可选:配置特定包的日志级别
log4j.logger.com.artisan=DEBUG

Code

java 复制代码
package com.artisan.jcl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class JavaCommonsLoggingTest {

    private static final Log logger = LogFactory.getLog(JavaCommonsLoggingTest.class);

    public static void main(String[] args) {
        logger.trace("This is a trace message");
        logger.debug("This is a debug message");
        logger.info("This is an info message");
        logger.warn("This is a warning message");
        logger.error("This is an error message");
        logger.fatal("This is a fatal message");
    }
}

输出


Example 3 : JCL 适配log4j2

Java - 日志体系_Apache Commons Logging(JCL)日志接口库_适配Log4j2 及 源码分析

Example 4 : JCL 桥接 logback

Java - 日志体系_Apache Commons Logging(JCL)日志接口库_桥接Logback 及 源码分析


7. 使用场景与优点

  • 适用于需要在多个日志框架之间切换的场景。
  • 提供了对遗留系统的支持,使其能够与现代日志框架协同工作。
  • 适合中间件开发,避免直接绑定特定的日志框架。

8. 常见问题

  • 为什么不直接使用SLF4J?

    JCL比SLF4J更早出现,仍被许多遗留系统使用。如果是全新项目,建议考虑SLF4J,它解决了JCL的一些局限性。

  • 性能是否有损耗?

    JCL的动态绑定机制在启动时可能略有开销,但运行时性能与直接使用日志实现接近。


9. 动态绑定机制源码分析

让我们以LogFactory.getLog(JavaCommonsLoggingTest.class) 为切入口 ,

java 复制代码
  /**
 * 获取指定类的日志记录器实例
 * 
 * @param clazz 要获取日志记录器的类
 * @return 指定类的日志记录器实例
 * @throws LogConfigurationException 如果日志配置存在错误,则抛出此异常
 */
public static Log getLog(final Class<?> clazz) throws LogConfigurationException {
    // 调用日志工厂的实例方法获取日志记录器
    return getFactory().getInstance(clazz);
}

成功 失败 开始 获取 LogFactory 实例 通过 LogFactory 获取日志记录器 返回日志记录器 抛出 LogConfigurationException


getFactory

重点看下: getFactory()

主要功能是根据一系列优先级规则查找并返回一个 LogFactory 实例。

  1. 获取类加载器:首先获取当前线程的上下文类加载器。
  2. 检查缓存 :如果该类加载器已经有一个对应的 LogFactory 实例,则直接返回该实例。
  3. 加载配置文件 :尝试从 commons-logging.properties 文件中读取配置信息。
  4. 确定是否使用TCCL :根据配置文件中的 use_tccl 属性决定是否使用线程上下文类加载器。
  5. 查找实现类
    • 首先尝试通过系统属性 org.apache.commons.logging.LogFactory 查找。
    • 如果未找到,尝试使用 JDK 1.3 的服务发现机制。
    • 如果仍未找到,尝试从配置文件中查找。
    • 最后,尝试使用默认的实现类 org.apache.commons.logging.impl.LogFactoryImpl
  6. 创建并缓存实例 :创建 LogFactory 实例并将其缓存。

成功 命中 未命中 开始 获取类加载器 检查缓存 返回缓存实例 加载配置文件 确定是否使用TCCL 查找实现类 系统属性查找 服务发现机制查找 配置文件查找 默认实现类 创建并缓存实例 返回实例

假设: 没有org.apache.commons.logging.LogFactory 这个系统配置项,classpath下没有包含META-INF/services/org.apache.commons.logging.LogFactory 这个文件的Jar包、没有commons-logging.properties 文件,只有commons-logging这个jar

LogFactoryImpl

我们来看下 LogFactoryImpl

java 复制代码
	    /** Log4JLogger class name */
    private static final String LOGGING_IMPL_LOG4J_LOGGER = "org.apache.commons.logging.impl.Log4JLogger";
    /** Jdk14Logger class name */
    private static final String LOGGING_IMPL_JDK14_LOGGER = "org.apache.commons.logging.impl.Jdk14Logger";
    /** Jdk13LumberjackLogger class name */
    private static final String LOGGING_IMPL_LUMBERJACK_LOGGER =
            "org.apache.commons.logging.impl.Jdk13LumberjackLogger";

    /** SimpleLog class name */
    private static final String LOGGING_IMPL_SIMPLE_LOGGER = "org.apache.commons.logging.impl.SimpleLog";


   private static final String[] classesToDiscover = {
            LOGGING_IMPL_JDK14_LOGGER,
            LOGGING_IMPL_SIMPLE_LOGGER
    };

可知: 默认实现为

java 复制代码
 LOGGING_IMPL_JDK14_LOGGER org.apache.commons.logging.impl.Jdk14Logger

log4j 不再是默认实现

commons-logging的动态绑定机制实现如上,但是这种机制的问题在哪儿呢,由于它使用了ClassLoader寻找和载入底层的日志库, 导致了象OSGI这样的框架无法正常工作,因为OSGI的不同的插件使用自己的ClassLoader。 OSGI的这种机制保证了插件互相独立,然而却使Apache Common-Logging无法工作 。 所以就有了Slf4j这种静态绑定的方案。


10. 总结

JCL为日志记录提供了一种统一的接口,虽然不如SLF4J现代化,但在历史遗留系统中仍有广泛的使用价值。如果需要简化日志实现的切换,JCL是一个可靠的选择。

相关推荐
xiezhr5 个月前
万字长文带你了解Java日志框架使用Java日志框架
java·log4j·logback·log4j2·java日志框架·slf4j·jul·jcl