Java - 日志体系_Apache Commons Logging(JCL)日志接口库
文章目录
- Apache Commons
- Apache Commons Proper
- 官网 Logging (Apache Commons Logging )
- 1. 什么是JCL?
- 2. JCL的主要特点
- 3. JCL的核心组件
- 4. JCL的实现机制
- 5. SimpleLog 简介
- 6. Code
- Example 1 : 默认日志实现 (JCL 1.3.2版本)
- Example 2 : JCL (1.2版本) + Log4J 【安全风险高,请勿使用】
- 7. 使用场景与优点
- 8. 常见问题
- 9. 动态绑定机制源码分析
- getFactory
- LogFactoryImpl
- 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 |
用于从 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 接口
提供通用的日志记录方法(如debug
、info
、warn
、error
、fatal
)。Log log = LogFactory.getLog(YourClass.class); log.info("信息日志"); log.error("错误日志");
-
LogFactory 类
用于创建Log
接口的实例。LogFactory
实现了日志系统的自动发现和绑定。
4. JCL的实现机制
JCL使用自动发现机制选择合适的日志实现:
- 首先检查类路径中是否存在Log4j,如果存在则使用Log4j (高版本的JCL已经移除了对log4j的支持)
- 如果找不到Log4j,JCL会检查
java.util.logging
并使用它。 - 如果前两个都不可用,则使用内置的
SimpleLog
作为默认实现。
可以通过配置文件commons-logging.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
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.3.2</version></dependency>
Example 1 : 默认日志实现 (JCL 1.3.2版本)
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)
<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
<!-- 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
# 设置根日志记录器的日志级别为 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
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");}
}
输出
7. 使用场景与优点
- 适用于需要在多个日志框架之间切换的场景。
- 提供了对遗留系统的支持,使其能够与现代日志框架协同工作。
- 适合中间件开发,避免直接绑定特定的日志框架。
8. 常见问题
-
为什么不直接使用SLF4J?
JCL比SLF4J更早出现,仍被许多遗留系统使用。如果是全新项目,建议考虑SLF4J,它解决了JCL的一些局限性。 -
性能是否有损耗?
JCL的动态绑定机制在启动时可能略有开销,但运行时性能与直接使用日志实现接近。
9. 动态绑定机制源码分析
让我们以LogFactory.getLog(JavaCommonsLoggingTest.class)
为切入口 ,
/*** 获取指定类的日志记录器实例* * @param clazz 要获取日志记录器的类* @return 指定类的日志记录器实例* @throws LogConfigurationException 如果日志配置存在错误,则抛出此异常*/
public static Log getLog(final Class<?> clazz) throws LogConfigurationException {// 调用日志工厂的实例方法获取日志记录器return getFactory().getInstance(clazz);
}
getFactory
重点看下: getFactory()
主要功能是根据一系列优先级规则查找并返回一个 LogFactory
实例。
- 获取类加载器:首先获取当前线程的上下文类加载器。
- 检查缓存:如果该类加载器已经有一个对应的
LogFactory
实例,则直接返回该实例。 - 加载配置文件:尝试从
commons-logging.properties
文件中读取配置信息。 - 确定是否使用TCCL:根据配置文件中的
use_tccl
属性决定是否使用线程上下文类加载器。 - 查找实现类:
- 首先尝试通过系统属性
org.apache.commons.logging.LogFactory
查找。 - 如果未找到,尝试使用 JDK 1.3 的服务发现机制。
- 如果仍未找到,尝试从配置文件中查找。
- 最后,尝试使用默认的实现类
org.apache.commons.logging.impl.LogFactoryImpl
。
- 首先尝试通过系统属性
- 创建并缓存实例:创建
LogFactory
实例并将其缓存。
假设: 没有org.apache.commons.logging.LogFactory
这个系统配置项,classpath下没有包含META-INF/services/org.apache.commons.logging.LogFactory
这个文件的Jar包、没有commons-logging.properties 文件,只有commons-logging
这个jar
LogFactoryImpl
我们来看下 LogFactoryImpl
,
/** 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};
可知: 默认实现为
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是一个可靠的选择。