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

文章目录

  • Pre
  • [Apache Commons](#Apache Commons)
    • [Apache Commons Proper](#Apache Commons Proper)
    • [Logging (Apache Commons Logging )](#Logging (Apache Commons Logging ))
  • [JCL 集成Log4j2](#JCL 集成Log4j2)
    • [添加 Maven 依赖](#添加 Maven 依赖)
    • [配置 Log4j2](#配置 Log4j2)
    • 验证集成
  • 源码分析
    • [1. Log4j-jcl 的背景](#1. Log4j-jcl 的背景)
    • [2. `log4j-jcl` 的工作原理](#2. log4j-jcl 的工作原理)
      • [2.1 替换默认的 `LogFactoryImpl`](#2.1 替换默认的 LogFactoryImpl)
      • [2.2 `LogFactoryImpl` 的实现](#2.2 LogFactoryImpl 的实现)
      • [2.3 LoggerContext 和 Logger 的初始化](#2.3 LoggerContext 和 Logger 的初始化)
      • [2.4 将 Log4j 2 的 Logger 封装成 Log4jLog](#2.4 将 Log4j 2 的 Logger 封装成 Log4jLog)
    • [3. 日志记录过程](#3. 日志记录过程)
    • 小结

Pre

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

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

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

Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J实现原理分析

Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成JUL 及 原理分析

Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成Log4j1.x 及 原理分析

Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成Log4j2.x 及 原理分析

Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成logback 及 原理分析


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
Email 用于从 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 集成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 的适配器包)
xml 复制代码
   <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 复制代码
 <?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>

验证集成

java 复制代码
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 实现类:

    plaintext 复制代码
    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 对象。具体实现如:

    java 复制代码
    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 实例。

    java 复制代码
    LogManager.getContext(cl, false);

    这个方法会在类加载时被调用,初始化 Log4j 2 的上下文环境,进而为每个日志记录器(Logger)创建一个上下文。

  • 然后,LoggerContext.getLogger(name) 会创建或返回一个日志记录器(Logger),这个 Logger 对象就是 Log4j 2 的原生日志记录器。

2.4 将 Log4j 2 的 Logger 封装成 Log4jLog

  • 最终,Log4j 2 的原生 Logger 对象被封装进 Log4jLog 类:

    java 复制代码
    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 提供的强大日志功能。

相关推荐
小小工匠8 天前
Java - 日志体系_Apache Commons Logging(JCL)日志接口库_桥接Logback 及 源码分析
logback·桥接·jcl
小小工匠10 天前
Java - 日志体系_Apache Commons Logging(JCL)日志接口库
jcl
white camel2 个月前
Java从入门到架构师_日志框架系列
java·logback·log4j2·日志·slf4j
枫叶_v5 个月前
【SpringBoot】10 日志持久化(log4j2)
spring boot·后端·log4j·log4j2·日志·日志持久化
tryCbest5 个月前
springCloudAlibaba整合log4j2
log4j2·cloudalibaba
xiezhr5 个月前
万字长文带你了解Java日志框架使用Java日志框架
java·log4j·logback·log4j2·java日志框架·slf4j·jul·jcl
Z3r4y8 个月前
【Web】log4j打JNDI专题刷题记录
java·log4j·web·ctf·log4j2
老马啸西风1 年前
log-01-日志组件之 Log4j 入门介绍
java·log4j·监控·log4j2·日志·log
京东云开发者1 年前
log4j2同步日志引发的性能问题
log4j2