文章目录
- Pre
- Apache Commons
- Apache Commons Proper
- Logging (Apache Commons Logging )
- JCL 集成logback
- POM依赖
- 配置文件 `logback.xml`
- 使用
- 源码分析
- `jcl-over-slf4j` 的工作原理
- 1. `LogFactory` 的实现
- 2. `SLF4JLogFactory` 和 `Log` 的实例化过程
- 3. `SLF4JLog` 和 `SLF4JLocationAwareLog`
- 4. 日志输出的流程
- 小结
Pre
Java - 日志体系_Apache Commons Logging(JCL)日志接口库
Java - 日志体系_Apache Commons Logging(JCL)日志接口库_适配Log4j2 及 源码分析
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 集成logback
POM依赖
- jcl-over-slf4j (替代了 commons-logging)
- slf4j-api
- logback-core
- logback-classic
通过 jcl-over-slf4j
替换 commons-logging
,从而让 commons-logging
使用 SLF4J
作为底层日志实现。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>2.0.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.16</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.5.15</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.15</version>
</dependency>
jcl-over-slf4j
:这个依赖项将commons-logging
的日志请求转发到 SLF4J 框架。slf4j-api
:SLF4J 的接口库,负责提供日志记录的 API。logback-core
和logback-classic
:这是 Logback 的核心和实现,负责具体的日志输出。
配置文件 logback.xml
logback.xml
文件用于定义日志输出的格式和方式。
<configuration>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} ||| %msg%n</pattern>
</encoder>
</appender>
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>application.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 可选:配置日志文件滚动 -->
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天滚动日志文件 -->
<fileNamePattern>application-%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 最多保留 30 天的日志文件 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 根日志记录器 -->
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="ROLLING_FILE" />
</root>
<!-- 可选:配置特定包的日志级别 -->
<logger name="com.artisan" level="info" />
</configuration>
使用
在代码中,通过 commons-logging
的 API 来记录日志,并且通过 SLF4J 和 Logback 完成实际的日志输出。
package com.artisan;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* commons-logging 与 logback 集成
*
*/
public class JclBridgeLogbackExample {
// commons logging 的 Log 和 LogFactory
private static final Log logger= LogFactory.getLog(JclBridgeLogbackExample.class);
public static void main( String[] args ) {
logger.trace("JclBridgeLogbackExample This is a trace message");
logger.debug("JclBridgeLogbackExample This is a debug message");
logger.info("JclBridgeLogbackExample This is an info message");
logger.warn("JclBridgeLogbackExample This is a warning message");
logger.error("JclBridgeLogbackExample This is an error message");
logger.fatal("JclBridgeLogbackExample This is a fatal message");
}
}
源码分析
jcl-over-slf4j
的工作原理
jcl-over-slf4j
的作用是将 commons-logging
的日志接口(例如 Log
和 LogFactory
)转换为 SLF4J
的实现。具体地,它将 commons-logging
的日志请求转发给 SLF4J
,而 SLF4J
则可以根据配置选择底层的日志框架(如 logback
)。
-
步骤一:将
commons-logging
转向SLF4J
jcl-over-slf4j
提供了一个LogFactory
类,该类实现了commons-logging
的LogFactory
接口,负责创建Log
实例。- 该类内部,
LogFactory
被静态化为SLF4JLogFactory
,即它总是创建SLF4JLogFactory
的实例,而不再使用commons-logging
自带的实现。
-
步骤二:使用
SLF4J
作为底层日志实现SLF4JLogFactory
内部调用LoggerFactory.getLogger(name)
来获取SLF4J
的Logger
实例。LoggerFactory
是SLF4J
提供的工厂类,负责返回一个底层日志记录器实例。- 一旦获取到
SLF4J
的Logger
实例,jcl-over-slf4j
将其封装成commons-logging
定义的Log
接口的实现,即SLF4JLog
或SLF4JLocationAwareLog
。 SLF4JLog
或SLF4JLocationAwareLog
通过委托的方式将实际的日志调用转发给SLF4J
的Logger
,而Logger
决定了最终使用哪个底层日志框架(如logback
)。
1. LogFactory
的实现
在 jcl-over-slf4j
中,LogFactory
被静态化为 SLF4JLogFactory
:
public abstract class LogFactory {
static LogFactory logFactory = new SLF4JLogFactory();
// 其他代码...
}
SLF4JLogFactory
是LogFactory
的实现,它负责创建Log
实例。LogFactory.getLog()
方法调用SLF4JLogFactory
中的newInstance()
方法来创建Log
实例。
2. SLF4JLogFactory
和 Log
的实例化过程
SLF4JLogFactory
实现了 LogFactory
接口,并重写了 newInstance()
方法来创建 Log
对象:
public class SLF4JLogFactory extends LogFactory {
public Log newInstance(String name) {
Logger slf4jLogger = LoggerFactory.getLogger(name);
Log newInstance;
if (slf4jLogger instanceof LocationAwareLogger) {
newInstance = new SLF4JLocationAwareLog((LocationAwareLogger) slf4jLogger);
} else {
newInstance = new SLF4JLog(slf4jLogger);
}
return newInstance;
}
}
LoggerFactory.getLogger(name)
创建了一个SLF4J
的Logger
实例(这背后通常是logback
)。- 如果
Logger
实现了LocationAwareLogger
,则会使用SLF4JLocationAwareLog
,它提供了更加详细的日志信息(如日志位置等)。 - 否则,使用普通的
SLF4JLog
实现。
3. SLF4JLog
和 SLF4JLocationAwareLog
SLF4JLog
和 SLF4JLocationAwareLog
是 Log
接口的实现,它们负责将 commons-logging
的日志方法(如 debug()
, info()
等)委托给 SLF4J
的 Logger
。这两个类的源码大致如下:
public class SLF4JLog implements Log {
private final Logger slf4jLogger;
public SLF4JLog(Logger slf4jLogger) {
this.slf4jLogger = slf4jLogger;
}
@Override
public void trace(Object message) {
slf4jLogger.trace(String.valueOf(message));
}
@Override
public void debug(Object message) {
slf4jLogger.debug(String.valueOf(message));
}
@Override
public void info(Object message) {
slf4jLogger.info(String.valueOf(message));
}
// 其他日志级别方法...
}
SLF4JLocationAwareLog
类似,只不过它会获取日志的调用位置(如类名、行号等)以提供更详细的日志信息。
4. 日志输出的流程
-
通过
commons-logging
API 写日志:- 使用
commons-logging
提供的Log
接口进行日志编写(例如LogFactory.getLog()
获取日志实例)。 - 调用
trace()
,debug()
,info()
等方法。
- 使用
-
日志请求转发给
SLF4J
:jcl-over-slf4j
将这些日志请求转发到SLF4J
的Logger
实例。
-
最终日志输出:
SLF4J
根据底层的配置选择具体的日志框架(如logback
),并将日志输出到目标(控制台、文件等)。
小结
jcl-over-slf4j
使commons-logging
可以使用SLF4J
作为底层日志实现,进而可以通过SLF4J
配置选择logback
作为实际的日志框架。LogFactory
和Log
被重定向到SLF4JLogFactory
和SLF4JLog
,这些类将日志请求转发给SLF4J
,而SLF4J
决定底层日志框架(如logback
)的使用。- 这种方式允许我们继续使用
commons-logging
API 进行日志记录,而底层的日志实现却是logback
,结合了两者的优势。