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

打印 上一主题 下一主题

主题 722|帖子 722|积分 2166



官网

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


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)。
    1. Log log = LogFactory.getLog(YourClass.class);
    2. log.info("信息日志");
    3. log.error("错误日志");
    复制代码
  • LogFactory 类
    用于创建Log接口的实例。LogFactory实现了日志系统的自动发现和绑定。

4. JCL的实现机制

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

  • 首先查抄类路径中是否存在Log4j,假如存在则利用Log4j (高版本的JCL已经移除了对log4j的支持)
  • 假如找不到Log4j,JCL会查抄java.util.logging并利用它。
  • 假如前两个都不可用,则利用内置的SimpleLog作为默认实现。
可以通过设置文件commons-logging.properties显式指定日志实现。例如:
  1. 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
  1.   <dependency>
  2.             <groupId>commons-logging</groupId>
  3.       <artifactId>commons-logging</artifactId>
  4.       <version>1.3.2</version>
  5.   </dependency>
复制代码
Example 1 : 默认日志实现 (JCL 1.3.2版本)

  1. package com.artisan.jcl;
  2. import org.apache.commons.logging.Log;
  3. import org.apache.commons.logging.LogFactory;
  4. public class JavaCommonsLoggingTest {
  5.     private static final Log log = LogFactory.getLog(JavaCommonsLoggingTest.class);
  6.     public static void main(String[] args) {
  7.         log.info("这是信息日志");
  8.         log.warn("这是警告日志");
  9.         log.error("这是错误日志");
  10.     }
  11. }
复制代码


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

log4j1从2005年11月更新到2012年3月, 最新的依赖(May 26, 2012)
  1. <dependency>
  2.     <groupId>log4j</groupId>
  3.     <artifactId>log4j</artifactId>
  4.     <version>1.2.17</version>
  5. </dependency>
复制代码
2015年8月5日,项目管理委员会公布Log4j 1.x已End Of Life 。发起用户利用Log4j 1升级到Apache Log4j 2

为了演示这种组合,我们将JCL降级到1.2版本
   pom
  1.    <!-- Jakarta Commons Logging -->
  2.         <dependency>
  3.             <groupId>commons-logging</groupId>
  4.             <artifactId>commons-logging</artifactId>
  5.             <version>1.2</version>
  6.         </dependency>
  7.         <!-- Log4j 核心依赖 -->
  8.         <dependency>
  9.             <groupId>log4j</groupId>
  10.             <artifactId>log4j</artifactId>
  11.             <version>1.2.17</version>
  12.         </dependency>
复制代码
  log4j.properties
  1. # 设置根日志记录器的日志级别为 DEBUG,并将其输出到控制台和文件
  2. log4j.rootLogger=DEBUG, console, file
  3. # 配置控制台输出
  4. log4j.appender.console=org.apache.log4j.ConsoleAppender
  5. log4j.appender.console.layout=org.apache.log4j.PatternLayout
  6. log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
  7. # 可选:配置日志文件滚动
  8. log4j.appender.file=org.apache.log4j.RollingFileAppender
  9. log4j.appender.file.File=application.log
  10. log4j.appender.file.MaxFileSize=10MB
  11. log4j.appender.file.MaxBackupIndex=10
  12. log4j.appender.file.layout=org.apache.log4j.PatternLayout
  13. log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
  14. # 可选:配置特定包的日志级别
  15. log4j.logger.com.artisan=DEBUG
复制代码
  Code
  1. package com.artisan.jcl;
  2. import org.apache.commons.logging.Log;
  3. import org.apache.commons.logging.LogFactory;
  4. public class JavaCommonsLoggingTest {
  5.     private static final Log logger = LogFactory.getLog(JavaCommonsLoggingTest.class);
  6.     public static void main(String[] args) {
  7.         logger.trace("This is a trace message");
  8.         logger.debug("This is a debug message");
  9.         logger.info("This is an info message");
  10.         logger.warn("This is a warning message");
  11.         logger.error("This is an error message");
  12.         logger.fatal("This is a fatal message");
  13.     }
  14. }
复制代码
  输出
  


7. 利用场景与长处



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

8. 常见问题



  • 为什么不直接利用SLF4J?
    JCL比SLF4J更早出现,仍被很多遗留系统利用。假如是全新项目,发起考虑SLF4J,它解决了JCL的一些范围性。
  • 性能是否有消耗?
    JCL的动态绑定机制在启动时大概略有开销,但运行时性能与直接利用日志实现靠近。

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

让我们以LogFactory.getLog(JavaCommonsLoggingTest.class) 为切入口 ,
  1.   /**
  2. * 获取指定类的日志记录器实例
  3. *
  4. * @param clazz 要获取日志记录器的类
  5. * @return 指定类的日志记录器实例
  6. * @throws LogConfigurationException 如果日志配置存在错误,则抛出此异常
  7. */
  8. public static Log getLog(final Class<?> clazz) throws LogConfigurationException {
  9.     // 调用日志工厂的实例方法获取日志记录器
  10.     return getFactory().getInstance(clazz);
  11. }
复制代码
   
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 ,
  1.             /** Log4JLogger class name */
  2.     private static final String LOGGING_IMPL_LOG4J_LOGGER = "org.apache.commons.logging.impl.Log4JLogger";
  3.     /** Jdk14Logger class name */
  4.     private static final String LOGGING_IMPL_JDK14_LOGGER = "org.apache.commons.logging.impl.Jdk14Logger";
  5.     /** Jdk13LumberjackLogger class name */
  6.     private static final String LOGGING_IMPL_LUMBERJACK_LOGGER =
  7.             "org.apache.commons.logging.impl.Jdk13LumberjackLogger";
  8.     /** SimpleLog class name */
  9.     private static final String LOGGING_IMPL_SIMPLE_LOGGER = "org.apache.commons.logging.impl.SimpleLog";
  10.    private static final String[] classesToDiscover = {
  11.             LOGGING_IMPL_JDK14_LOGGER,
  12.             LOGGING_IMPL_SIMPLE_LOGGER
  13.     };
复制代码
可知: 默认实现为
  1. 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是一个可靠的选择。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

灌篮少年

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表