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

news2025/1/2 22:56:28

文章目录

  • Pre
  • Apache Commons
    • Apache Commons Proper
    • Logging (Apache Commons Logging )
  • JCL 集成Log4j2
    • 添加 Maven 依赖
    • 配置 Log4j2
    • 验证集成
  • 源码分析
    • 1. Log4j-jcl 的背景
    • 2. `log4j-jcl` 的工作原理
      • 2.1 替换默认的 `LogFactoryImpl`
      • 2.2 `LogFactoryImpl` 的实现
      • 2.3 LoggerContext 和 Logger 的初始化
      • 2.4 将 Log4j 2 的 Logger 封装成 Log4jLog
    • 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.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 提供的强大日志功能。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2268060.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

brupsuite的基础用法常用模块(1)

proxy模块&#xff1a; Options: 设置代理端口&#xff0c;默认为8080端口&#xff0c;若8080端口被占用可在该界面更改代理端口. HTTP history: 拦截的历史请求&#xff0c;右键可做更多操作&#xff0c;很多操作与其他模块有关。&#xff08;清除历史的话右键选择clear p…

概率统计与随机过程--作业7

编程题 分别使用混合高斯聚类算法&#xff08;GMM&#xff09;和K-Means聚类算法将agricultural_economy.xlsx文件中的9个样本聚成2类&#xff08;可以使用sklearn的GaussianMixture和KMeans&#xff09;&#xff0c;用不同颜色绘图显示各类样本点&#xff0c;并与“最短距离聚…

【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor

IJob&#xff1a;开启单个线程进行计算&#xff0c;线程内不允许对同一个数据进行操作&#xff0c;也就是如果你想用多个IJob分别计算&#xff0c;将其结果存储到同一个NativeArray<int>数组是不允许的&#xff0c;所以不要这样做&#xff0c;如下例子就是反面教材&#…

MicroDiffusion——采用新的掩码方法和改进的 Transformer 架构,实现了低预算的扩散模型

介绍 论文地址&#xff1a;https://arxiv.org/abs/2407.15811 现代图像生成模型擅长创建自然、高质量的内容&#xff0c;每年生成的图像超过十亿幅。然而&#xff0c;从头开始训练这些模型极其昂贵和耗时。文本到图像&#xff08;T2I&#xff09;扩散模型降低了部分计算成本&a…

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

文章目录 Pre官网集成Log4j1.x步骤POM依赖使用第一步&#xff1a;编写 Log4j 配置文件第二步&#xff1a;代码 原理分析1. 获取对应的 ILoggerFactory2. 根据 ILoggerFactory 获取 Logger 实例3. 日志记录过程 小结 Pre Java - 日志体系_Apache Commons Logging&#xff08;JC…

详解VHDL如何编写Testbench

1.概述 仿真测试平台文件(Testbench)是可以用来验证所设计的硬件模型正确性的 VHDL模型&#xff0c;它为所测试的元件提供了激励信号&#xff0c;可以以波形的方式显示仿真结果或把测试结果存储到文件中。这里所说的激励信号可以直接集成在测试平台文件中&#xff0c;也可以从…

Linux day 11 28

一.Linux简介 1.1 Linux介绍 Linux 是一套免费使用和自由传播的操作系统。说到操作系 统&#xff0c;大家比较熟知的应该就是 Windows 和 MacOS 操作系统&#xff0c; 我们今天所学习的 Linux 也是一款操作系统。 1.2 Linux发展历史 时间&#xff1a; 1991 年 地点&#xf…

【深度学习环境】NVIDIA Driver、Cuda和Pytorch(centos9机器,要用到显示器)

文章目录 一 、Anaconda install二、 NIVIDIA driver install三、 Cuda install四、Pytorch install 一 、Anaconda install Step 1 Go to the official website: https://www.anaconda.com/download Input your email and submit. Step 2 Select your version, and click i…

Lecture 17

10’s Complement Representation 主要内容&#xff1a; 1. 10’s 补码表示: • 10’s 补码表示法需要指定表示的数字位数&#xff08;用 n 表示&#xff09;。 • 表示的数字取决于 n 的位数&#xff0c;这会影响具体数值的解释。 2. 举例: • 如果采用 3 位补码&…

惠州市政数局局长杨伟斌:惠州市公共数据授权运营模式探索

近期&#xff0c;2024数字资产管理大会召开。会上&#xff0c;惠州市政务服务和数据管理局局长杨伟斌在会上做了题为基于“隐私计算区块链”的惠州市公共数据授权运营模式探索主旨演讲&#xff0c;从三个方面展开&#xff0c;一是建制度汇数据&#xff0c;二是夯基础保安全&…

C#编写的金鱼趣味小应用 - 开源研究系列文章

今天逛网&#xff0c;在GitHub中文网上发现一个源码&#xff0c;里面有这个金鱼小应用&#xff0c;于是就下载下来&#xff0c;根据自己的C#架构模板进行了更改&#xff0c;最终形成了这个例子。 1、 项目目录&#xff1b; 2、 源码介绍&#xff1b; 1) 初始化&#xff1b; 将样…

探索贝叶斯魔法和误差的秘密

引言 今天我们要一起学习两个神秘的魔法概念&#xff1a;贝叶斯魔法和误差的秘密。这些概念听起来可能有点复杂&#xff0c;但别担心&#xff0c;我会用最简单的方式来解释它们。 一、贝叶斯魔法 贝叶斯魔法是一种预测的魔法&#xff0c;它帮助我们理解在不确定的情况下事情…

深度学习blog-卷积神经网络(CNN)

卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种广泛应用于计算机视觉领域&#xff0c;如图像分类、目标检测和图像分割等任务中的深度学习模型。 1. 结构 卷积神经网络一般由以下几个主要层组成&#xff1a; 输入层&#xff1a;接收…

深度学习笔记(6)——循环神经网络RNN

循环神经网络 RNN 核心思想:RNN内部有一个“内部状态”,随着序列处理而更新 h t f W ( h t − 1 , x t ) h_tf_W(h_{t-1},x_t) ht​fW​(ht−1​,xt​) 一般来说 h t t a n h ( W h h h t − 1 W x h x t ) h_ttanh(W_{hh}h_{t-1}W_{xh}x_t) ht​tanh(Whh​ht−1​Wxh​xt…

最新版Edge浏览器加载ActiveX控件技术——alWebPlugin中间件V2.0.28-迎春版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

【前端,TypeScript】TypeScript速成(三):枚举类型

枚举类型 枚举类型是 TypeScript 相较于 JavaScript 而言特有的部分。一个简单的枚举声明如下&#xff1a; enum HTTPStatus {OK,NOT_FOUND,INTERNAL_STATUS_ERROR, }与编译成 JavaScript 的代码相比较&#xff1a; 显然 TypeScript 非常的简洁。 尝试使用上述枚举类型&…

Webpack学习笔记(6)

首先搭建一个基本的webpack环境&#xff1a; 执行npm init -y&#xff0c;创建pack.json&#xff0c;保存安装包的一些信息 执行npm install webpack webpack-cli webpack-dev-server html-webpack-plugin -D&#xff0c;出现node_modules和package-lock.json。 1.source-Ma…

Java高频面试之SE-06

hello啊&#xff0c;各位老6&#xff01;&#xff01;&#xff01;本牛马baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; 访问修饰符 public、private、protected的区别是什么&#xff1f; 在Java中&#xff0c;访问修饰符用于控制类、方法和变量的访问权限。主要的访…

报表工具DevExpress Reporting v24.2亮点 - AI功能进一步强化

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表。 报表工具DevExpress Reporting v24.2将于近期发…