自学内容网 自学内容网

Java - 日志体系_Apache Commons Logging(JCL)日志接口库_适配Log4j2 及 源码分析

在这里插入图片描述


Pre

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


Apache Commons

官网:Apache Commons

在这里插入图片描述

Apache Commons Proper

Commons Proper 致力于一个主要目标: 创建和维护可重用的 Java 组件。这 Commons Proper 是一个协作和共享的地方,其中 来自整个 Apache 社区的开发人员都可以 一起讨论由 Apache 项目共享的项目,以及 Apache 用户。

共享资源开发人员将努力确保他们的 组件对其他库的依赖性最小,因此 这些组件可以轻松部署。此外,共享资源 组件将尽可能保持其接口稳定,因此 Apache 用户(包括其他 Apache 项目)可以实现 这些组件。

在这里插入图片描述

组件描述最新 Maven 版本发布版本发布日期
BCEL字节码工程库 - 分析、创建和操作 Java 类文件6.10.06.10.02024-07-23
BeanUtilsJava 反射和 introspection API 的易用封装1.9.41.9.42019-08-13
BSFBean 脚本框架 - 提供对脚本语言的接口,包括 JSR-2233.13.12010-06-24
CLI命令行参数解析器1.9.01.9.02024-08-14
Codec通用的编码/解码算法(例如音标、base64、URL)1.17.11.17.12024-07-15
Collections扩展或增强 Java 集合框架4.5.0-M34.5.0-M32024-12-18
Compress定义用于处理 tar、zip 和 bzip2 文件的 API1.27.11.27.12024-08-20
Configuration用于读取各种格式的配置/偏好文件2.11.02.11.02024-06-10
Crypto一个针对 AES-NI 优化的加密库,包装了 OpenSSL 或 JCE 算法实现1.2.01.2.02023-01-23
CSV处理逗号分隔值文件的组件1.12.01.12.02024-09-25
Daemon为 Unix 守护进程般的 Java 代码提供替代调用机制1.3.41.3.42023-05-12
DBCP数据库连接池服务2.13.02.13.02024-12-02
DbUtilsJDBC 辅助库1.8.11.8.12023-09-14
DigesterXML 到 Java 对象的映射工具3.23.22011-12-13
Email用于从 Java 发送电子邮件的库2.0.0-M12.0.0-M12024-06-27
Exec用于处理外部进程执行和环境管理的 API1.4.01.4.02024-01-05
FileUpload为您的 servlets 和 Web 应用提供文件上传功能1.51.52023-12-27
FileUpload2为您的 servlets 和 Web 应用提供文件上传功能(版本 2)2.0.0-M12.0.0-M12023-07-19
Geometry空间和坐标处理1.01.02021-08-21
Imaging一个纯 Java 图像库(之前称为 Sanselan)1.0.0-alpha51.0.0-alpha52024-04-18
IO一组 I/O 工具类2.18.02.18.02024-11-19
JCIJava 编译器接口1.11.12013-10-14
JCSJava 缓存系统3.2.13.2.12024-05-27
Jelly基于 XML 的脚本和处理引擎1.0.11.0.12017-09-25
Jexl扩展 JSTL 表达式语言的表达式语言3.4.03.4.02024-06-05
JXPath使用 XPath 语法操作 Java Beans 的工具集1.31.32008-08-14
Lang为 java.lang 类提供额外的功能3.17.03.17.02024-08-29
Logging包装了多种日志 API 实现1.3.41.3.42024-08-19
Math轻量级、自包含的数学和统计学组件4.0-beta14.0-beta12022-12-20
Net一组网络工具类和协议实现3.11.13.11.12024-06-10
Numbers数字类型(复数、四元数、分数)和工具(数组、组合数学等)1.21.22024-08-12
Pool通用对象池组件2.12.02.12.02023-09-30
RDFRDF 1.1 的通用实现,可由 JVM 上的系统实现0.5.00.5.02017-12-23
RNG随机数生成器的实现1.61.62024-07-15
SCXMLSCXML 规范的实现,旨在创建和维护 Java SCXML 引擎0.90.92008-12-01
Statistics统计学工具1.11.12024-08-20
TextApache Commons Text 是一个专注于字符串操作的算法库1.13.01.13.02024-12-13
Validator用于在 XML 文件中定义验证器和验证规则的框架1.9.01.9.02024-05-28
VFS虚拟文件系统组件,用于将文件、FTP、SMB、ZIP 等视为一个逻辑文件系统2.9.02.9.02021-07-21
Weaver提供一种简单的方式来增强(织入)已编译的字节码2.02.02018-09-07

Logging (Apache Commons Logging )

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

组件描述最新 Maven 版本发布版本发布日期
Logging包装了多种日志 API 实现1.3.41.3.42024-08-19

JCL 集成Log4j2

Commons Logging 是一个用于日志记录的抽象层,它允许开发人员通过一个统一的接口在不同的日志框架(如 Log4j、Logback、JDK Logging 等)之间切换。

Log4j2 是一个流行的日志框架,它提供了比 Log4j 更高的性能和更丰富的功能。将 Commons LoggingLog4j2 集成,意味着使用 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.xmllog4j2.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 和  LogFactory
    private 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 LoggingLog4j2 集成,我们可以在保持原有 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 LoggingLog 接口来记录日志(如 log.infolog.error),而 log4j-jcl 适配器会将这些日志请求转发到 Log4j 2 系统。

  • log4j-jcl 适配器:通过引入 log4j-jcl 适配器,Commons Logging 会使用 Log4j 2.x 的实现,而不需要修改原有的 Commons Logging API 代码。


那 如何通过 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-jclMETA-INF/services/org.apache.commons.logging.LogFactory 文件指明了使用 log4j-jcl 中的 LogFactoryImpl 实现类:

    org.apache.logging.log4j.jcl.LogFactoryImpl
    

    这就告诉 Commons Logging,当它需要实例化 LogFactory 时,使用 LogFactoryImpl,而不是默认的实现。
    在这里插入图片描述

2.2 LogFactoryImpl 的实现

  • LogFactoryImplCommons Logging 中的 LogFactory 的实现,负责创建适当的 Log 实例。它的核心逻辑是将 Commons LoggingLog 接口与 Log4j 2 的日志系统连接起来。

  • LogFactoryImpl 中有一个 LoggerAdapter<Log> 成员,这个适配器类的作用是将 Log4j 2 的 Logger 对象包装成 Commons LoggingLog 接口。

    其中,LogAdapter 是一个封装类,最终将 Log4j 2 的原生 Logger 对象封装成 Commons LoggingLog 对象。具体实现如:

    public class LogAdapter extends AbstractLoggerAdapter<Log> {
        @Override
        protected Log newLogger(final String name, final LoggerContext context) {
            return new Log4jLog(context.getLogger(name));
        }
    
        @Override
        protected 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 LoggingLog 接口,所有日志请求都会委托给内部的 Log4j 2 Logger 对象来处理。

3. 日志记录过程

当通过 Commons Logging 记录日志时(例如使用 LogFactory.getLog() 获取 Log 对象),日志会经过以下几个步骤:

  1. Code:发起日志记录请求。
  2. Commons Logging:接收用户请求,加载并初始化日志工厂。
  3. log4j-jcl:作为适配器,提供 LogFactoryImpl 实现。
  4. LogFactoryImpl:创建日志适配器 LoggerAdapter
  5. LoggerAdapter:使用 LogManager 初始化 LoggerContext,从中获取原生 Log4j 2 Logger
  6. Log4jLog:将 Log4j 2 的 Logger 对象包装成 Commons Logging 的接口实现。
  7. Log4j 2 Logger:通过 Log4j 2 的 Logger,日志会被实际记录并输出,通常是通过 log4j2.xml 中定义的 appender 进行输出。

小结

  • 核心流程Commons Logging -> LogFactoryImpl -> LogAdapter -> Log4j 2 Logger -> Log4jLog -> 记录日志。
  • log4j-jcl 通过 LogFactoryImplLogAdapterCommons Logging 的接口调用转发到 Log4j 2,实现了无缝集成。
  • 通过使用 LoggerContextLoggerLog4j 2 实现了高效的日志记录系统,同时通过适配器模式保持与 Commons Logging 的兼容性。

通过这个机制,项目可以无缝地使用 Commons Logging API,同时享受 Log4j 2 提供的强大日志功能。

在这里插入图片描述


原文地址:https://blog.csdn.net/yangshangwei/article/details/144777697

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!