文章目录
- Pre
- Apache Commons
- Apache Commons Proper
- Logging (Apache Commons Logging )
 
- JCL 集成Log4j2
- 添加 Maven 依赖
- 配置 Log4j2
- 验证集成
 
- 源码分析
- 1. Log4j-jcl 的背景
- 2. `log4j-jcl` 的工作原理
- 2.1 替换默认的 `LogFactoryImpl`
- 2.2 `LogFactoryImpl` 的实现
- 2.3 LoggerContext 和 Logger 的初始化
- 2.4 将 Log4j 2 的 Logger 封装成 Log4jLog
 
- 3. 日志记录过程
- 小结
 

Pre
Java - 日志体系_Apache Commons Logging(JCL)日志接口库
Java - 日志体系_Apache Commons Logging(JCL)日志接口库_适配Log4j2 及 源码分析
Java - 日志体系_Apache Commons Logging(JCL)日志接口库_桥接Logback 及 源码分析
Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J实现原理分析
Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成JUL 及 原理分析
Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成Log4j1.x 及 原理分析
Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成Log4j2.x 及 原理分析
Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成logback 及 原理分析
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 | 
| 用于从 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 | 
JCL 集成Log4j2
Commons Logging 是一个用于日志记录的抽象层,它允许开发人员通过一个统一的接口在不同的日志框架(如 Log4j、Logback、JDK Logging 等)之间切换。
Log4j2 是一个流行的日志框架,它提供了比 Log4j 更高的性能和更丰富的功能。将 Commons Logging 与 Log4j2 集成,意味着使用 Commons Logging 的 API 来实现日志记录,同时使用 Log4j2 作为底层日志框架。

添加 Maven 依赖
- commons-logging
- log4j-api (log4j2 的 API 包)
- log4j-core (log4j2 的 API 实现包)
- log4j-jcl (log4j2 与 commons-logging 的适配器包)
   <dependencies><!-- Apache Commons Logging --><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.3.4</version></dependency><!-- Log4j 2.x --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.24.3</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.24.3</version></dependency><!-- Log4j 2.x API adapter for Commons Logging --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-jcl</artifactId><version>2.24.3</version></dependency></dependencies>
不需要在代码中做任何更改,只要确保依赖关系配置正确,Commons Logging 就会自动通过适配器与 Log4j2 进行集成。
配置 Log4j2
接下来,需要创建 Log4j2 的配置文件,通常是 log4j2.xml 或 log4j2.properties,并将其放置在 src/main/resources 目录下。
 <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"><Appenders><!-- 控制台输出 --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L >>> %m%n"/></Console><!-- 文件输出 --><RollingFile name="RollingFile" fileName="logs/app.log"filePattern="logs/app-%d{yyyy-MM-dd}.log"><PatternLayout><pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n</pattern></PatternLayout><Policies><TimeBasedTriggeringPolicy/></Policies></RollingFile></Appenders><Loggers><!-- 根日志级别设置为info --><Root level="info"><AppenderRef ref="Console"/><AppenderRef ref="RollingFile"/></Root></Loggers>
</Configuration>
验证集成
package com.artisan;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;/***   commons-logging 与 log4j2 集成**/
public class JclAdapterLog4j2Example {// commons logging 的 Log 和  LogFactoryprivate static final Log logger= LogFactory.getLog(JclAdapterLog4j2Example.class);public static void main( String[] args ) {logger.trace("Log4JTest This is a trace message");logger.debug("Log4JTest This is a debug message");logger.info("Log4JTest This is an info message");logger.warn("Log4JTest This is a warning message");logger.error("Log4JTest This is an error message");logger.fatal("Log4JTest This is a fatal message");}
} 可以看到输出到控制台的日志,并且格式和日志级别等都会由
 可以看到输出到控制台的日志,并且格式和日志级别等都会由 Log4j2 控制。

 日志文件中日志
源码分析
通过将 Commons Logging 和 Log4j2 集成,我们可以在保持原有 Commons Logging API 的同时,享受 Log4j2 提供的高效性能和强大功能。只需添加相关依赖并正确配置 log4j2.xml,即可顺利完成集成。
让我们一起来探究下源码实现
- commons-logging:这是- Commons Logging的核心库,提供了日志抽象。
- log4j-api:这是 Log4j 2 的 API 包,提供日志记录的接口。
- log4j-core:这是 Log4j 2 的核心实现包,负责具体的日志记录、输出等功能。
- log4j-jcl:这是 Log4j 2 提供的与- Commons Logging的适配器包,使得- Commons Logging可以通过 Log4j 2 进行日志记录。

-  Commons Logging使用:确保我们在代码中依然使用Commons Logging的Log接口来记录日志(如log.info和log.error),而log4j-jcl适配器会将这些日志请求转发到 Log4j 2 系统。
-  log4j-jcl适配器:通过引入log4j-jcl适配器,Commons Logging会使用 Log4j 2.x 的实现,而不需要修改原有的Commons LoggingAPI 代码。
那 如何通过 log4j-jcl 适配器将 Commons Logging 转发给 Log4j 2 的日志实现的呢?
1. Log4j-jcl 的背景
-  Commons Logging 作为一个通用的日志抽象层,最初设计上并没有专门为 Log4j 2 提供支持。其默认实现使用了 LogFactoryImpl类,并通过 SPI (Service Provider Interface) 机制去查找合适的LogFactory实现,这个过程通常是基于类路径中可用的日志框架进行加载。
-  然而,原始的 Commons Logging并没有提供对Log4j 2的直接支持,它只能支持Log4j 1.x或其他日志框架。因此,log4j-jcl 作为一个适配器包应运而生,用来将Commons Logging的请求转发到Log4j 2。
2. log4j-jcl 的工作原理
 
commons-logging 原始的 jar 包中使用了默认的 LogFactoryImpl 作为 LogFactory,该默认的 LogFactoryImpl 中的 classesToDiscover 并没有 log4j2 对应的 Log 实现类。
 
所以我们就不能使用这个原始包中默认的 LogFactoryImpl 了,需要重新指定一个,并且需要给出一个 apache 的 Log 实现(该 Log 实现是用于 log4j2 的),所以就产生了 log4j-jcl 这个 jar 包
2.1 替换默认的 LogFactoryImpl
 
-  Commons Logging在初始化时,会通过SPI机制查找并加载LogFactory实现。默认情况下,它会加载LogFactoryImpl,但由于 Log4j 2 不在Commons Logging默认实现类中,所以我们需要通过log4j-jcl替换默认的LogFactoryImpl。
-  log4j-jcl的META-INF/services/org.apache.commons.logging.LogFactory文件指明了使用log4j-jcl中的LogFactoryImpl实现类:org.apache.logging.log4j.jcl.LogFactoryImpl这就告诉 Commons Logging,当它需要实例化LogFactory时,使用LogFactoryImpl,而不是默认的实现。
  
2.2 LogFactoryImpl 的实现
 
-  LogFactoryImpl是Commons Logging中的LogFactory的实现,负责创建适当的Log实例。它的核心逻辑是将Commons Logging的Log接口与Log4j 2的日志系统连接起来。
-  LogFactoryImpl中有一个LoggerAdapter<Log>成员,这个适配器类的作用是将 Log4j 2 的Logger对象包装成Commons Logging的Log接口。其中, LogAdapter是一个封装类,最终将 Log4j 2 的原生Logger对象封装成Commons Logging的Log对象。具体实现如:public class LogAdapter extends AbstractLoggerAdapter<Log> {@Overrideprotected Log newLogger(final String name, final LoggerContext context) {return new Log4jLog(context.getLogger(name));}@Overrideprotected LoggerContext getContext() {return getContext(ReflectionUtil.getCallerClass(LogFactory.class));} }- newLogger方法会使用 Log4j 2 的- LoggerContext.getLogger(name)获取 Log4j 2 的原生- Logger实例,然后将其包装成- Log4jLog实例。
- getContext方法通过- LogManager.getContext()初始化 Log4j 2 的- LoggerContext对象,它是 Log4j 2 中的核心对象,负责管理所有日志记录器。
 
2.3 LoggerContext 和 Logger 的初始化
-  Log4j 2 在初始化时,首先通过 LogManager.getContext()获取一个LoggerContext实例。LoggerContext是 Log4j 2 的核心对象,负责创建和管理Logger实例。LogManager.getContext(cl, false);这个方法会在类加载时被调用,初始化 Log4j 2 的上下文环境,进而为每个日志记录器( Logger)创建一个上下文。
-  然后, LoggerContext.getLogger(name)会创建或返回一个日志记录器(Logger),这个Logger对象就是 Log4j 2 的原生日志记录器。
2.4 将 Log4j 2 的 Logger 封装成 Log4jLog
-  最终,Log4j 2 的原生 Logger对象被封装进Log4jLog类:return new Log4jLog(context.getLogger(name));Log4jLog是一个适配器,它实现了Commons Logging的Log接口,所有日志请求都会委托给内部的 Log4j 2Logger对象来处理。
3. 日志记录过程
当通过 Commons Logging 记录日志时(例如使用 LogFactory.getLog() 获取 Log 对象),日志会经过以下几个步骤:
- Code:发起日志记录请求。
- Commons Logging:接收用户请求,加载并初始化日志工厂。
- log4j-jcl:作为适配器,提供- LogFactoryImpl实现。
- LogFactoryImpl:创建日志适配器- LoggerAdapter。
- LoggerAdapter:使用- LogManager初始化- LoggerContext,从中获取原生- Log4j 2 Logger。
- Log4jLog:将 Log4j 2 的- Logger对象包装成- Commons Logging的接口实现。
- Log4j 2 Logger:通过 Log4j 2 的- Logger,日志会被实际记录并输出,通常是通过- log4j2.xml中定义的 appender 进行输出。
小结
- 核心流程:Commons Logging->LogFactoryImpl->LogAdapter->Log4j 2 Logger->Log4jLog-> 记录日志。
- log4j-jcl通过- LogFactoryImpl和- LogAdapter将- Commons Logging的接口调用转发到- Log4j 2,实现了无缝集成。
- 通过使用 LoggerContext和Logger,Log4j 2实现了高效的日志记录系统,同时通过适配器模式保持与Commons Logging的兼容性。
通过这个机制,项目可以无缝地使用 Commons Logging API,同时享受 Log4j 2 提供的强大日志功能。
