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

news/2024/12/24 14:02:59 标签: JCL

文章目录

  • 官网
  • 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. 总结

在这里插入图片描述


官网

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

在这里插入图片描述


JCL_17">1. 什么是JCL

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


JCL_22">2. JCL的主要特点

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

JCL_30">3. JCL的核心组件

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

    Log log = LogFactory.getLog(YourClass.class);
    log.info("信息日志");
    log.error("错误日志");
    
  • LogFactory 类
    用于创建Log接口的实例。LogFactory实现了日志系统的自动发现和绑定。


JCL_44">4. JCL的实现机制

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

  1. 首先检查类路径中是否存在Log4j,如果存在则使用Log4j。
  2. 如果找不到Log4j,JCL会检查java.util.logging并使用它。
  3. 如果前两个都不可用,则使用内置的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>

JCL_132_79">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("这是错误日志");
    }
}

在这里插入图片描述


JCL_12__Log4J____107">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);
}

成功
失败
开始
获取 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

	    /** 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是一个可靠的选择。

在这里插入图片描述


http://www.niftyadmin.cn/n/5797873.html

相关文章

leetcode hot100 螺旋矩阵

54. 螺旋矩阵 已解答 中等 相关标签 相关企业 提示 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素 class Solution(object): def spiralOrder(self, matrix): """ :type matrix: List[List[int]]…

霍尔传感器在VR虚拟现实技术上的应用

在当今科技飞速发展的时代&#xff0c;虚拟现实&#xff08;VR&#xff09;技术正以前所未有的速度不断革新与拓展应用领域。 从沉浸式的游戏体验到专业的模拟训练&#xff0c;从虚拟的艺术创作空间到远程协作的工作场景&#xff0c;VR 已逐渐渗透到人们生活与工作的多个层面&…

游戏关卡设计方法的杂感

1、正规思路是&#xff1a;先写设计文档&#xff0c;画平面图&#xff0c;再做白模关卡&#xff0c;再做正规模型的关卡。 一步步扩大。 当然是有道理的&#xff0c;从小到大&#xff0c; 但实际上这需要很强的想象力&#xff0c;很多细节靠脑补&#xff0c;初学者很难做好。…

基于Spring Boot的个性化推荐外卖点餐系统

一、系统概述 该系统旨在为用户提供便捷、个性化的外卖点餐体验&#xff0c;同时为商家提供高效、智能的餐饮管理服务。通过利用Spring Boot框架的稳定性和可扩展性&#xff0c;系统实现了前后端分离的开发模式&#xff0c;支持多种设备和平台&#xff0c;确保用户在不同场景下…

conda 环境激活后,pip 版本没有切换到你预期的版本。这是 Windows 上使用 Conda 时一个比较常见的困扰。

conda 环境激活后&#xff0c;pip 版本没有切换到你预期的版本。这是 Windows 上使用 Conda 时一个比较常见的困扰。原因在于&#xff0c;环境变量的优先级问题。 Conda 环境机制: Conda 环境通过修改环境变量来实现 Python 和包的隔离。当你激活一个环境时&#xff0c;Conda 会…

Aec-Library-Website 项目常见问题解决方案

Aec-Library-Website 项目常见问题解决方案 Aec-Library-Website This is an Open-Source Library Website in which you get Resources to learn different topics, Donate book section to donate your old books, and a Book issue section to keep a record of all the bo…

外连接转AntiJoin的应用场景与限制条件 | OceanBase SQL 查询改写系列

在《SQL 改写系列&#xff1a;外连接转内连接的常见场景与错误》一文中&#xff0c;我们了解到谓词条件可以过滤掉连接结果中的 null 情形的&#xff0c;将外连接转化为内连接的做法是可行的&#xff0c;正如图1中路径(a)所示。此时&#xff0c;敏锐的你或许会进一步思考&#…

【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?

文章目录 前言问题描述问题分析问题解决1.允许所有用户上传驱动文件2.如果是想只上传白名单的驱动 前言 该方法适合永洪BI系列产品&#xff0c;包括不限于vividime desktop&#xff0c;vividime z-suit&#xff0c;vividime x-suit产品。 问题描述 当我们连接数据源的时候&a…