Skip to content

Spring 整合日志框架 Log4j2

对于一款软件而言,日志记录都是十分重要的。它不仅能够监控程序的运行情况,周期性的记录到文件中,还能够跟踪程序中代码的运行轨迹,向文件或控制台打印代码的调试信息。当程序出现错误时,日志记录可以帮助开发人员及时定位问题,因此对开发人员来说,日志记录更是尤为重要。

Spring 5 框架自带了通用的日志封装,但是我们依然可以整合其他的日志框架对日志进行记录,其中最广为人知的就是大名鼎鼎的 Log4j。

Log4j 是 Apache 提供的一款开源的强有力的 Java 日志记录工具。它可以通过配置文件灵活、细致地控制日志的生成过程,例如日志级别、日志的输出类型、日志的输出方式以及输出格式等。

Log4j 共有两个大版本,如下表所示。

版本时间说明
Log4j 1.x1999 年至 2015 年即我们常说的 Log4j, 它于 1999 年首次发布,就迅速成为有史以来最常用的日志框架。

2015 年 8 月 5 日,Apache Logging Services 宣布 Log4j 1.x 生命周期结束,其代码库不再发布更新,并鼓励用户升级到 Log4j 2.x。
Log4j 2.x2014 年至今即我们常说的 Log4j2,2014 年 Log4j 2.x 作为 Log4j 1.x 的替代品发布。

Log4j 2.x 是对 Log4j 1.x 的重大升级,它完全重写了 Log4j 的日志实现,比 Log4j 1.x 效率更高、更可靠且更易于开发和维护。此外,Log4j 2.x 还对 Logback 进行了许多改进,修复了 Logback 架构中的一些固有问题,目前已经更新到 2.17.1 版本。

Spring 整合 Log4j2

Spring 5 是基于 Java 8 实现的,其自身作了不少的优化,将许多不建议使用的类和方法从代码库中删除,其中就包括了 Log4jConfigListener(Spring 加载 Log4j  配置的监听器)。因此从 Spring 5 开始就不在支持对 Log4j 的整合,而更加推荐我们通过 Log4j2 进行日志记录。

下面我们们就来介绍下 Spring 是如何整合 Log4j2 的。

  1. 新建一个名为 my-spring-log4j-demo 的 Spring 项目,并将与 Spring 相关的 Jar 包导入到该项目中。

  2. 使用浏览器访问 Log4j2 官网,点击左侧导航栏中的 Download,跳转到 Log4j2 的下载页面。


图1:Log4j2 下载页面

  1. 我们根据自身操作系统的不同,选择不同的压缩包
  • apache-log4j-2.xx.x-bin.zip:为 Log4j2 为 Windows 系统提供的的压缩包。
  • apache-log4j-2.xx.x-bin.tar.gz:为 Log4j2 为 linux、MacOsX 系统提供的压缩包。

特别注意:由于 Log4j2 在 2021 年 12 月 10 日被曝存在远程代码执行漏洞,所有 Apache Log4j 2.x <= 2.14.1 版本均受到影响。随后,Log4j2 官方对此漏洞进行了了修复,因此我们在引入 Log4j2 的依赖时,尽量选择最新版本。编写本教程时,Log4j2 的最新版本为 Log4j 2.17.1,因此这里就以此版本为例进行讲解。

  1. 对下载完成的压缩包进行解压,并将以下 3 个依赖包导入到 my-spring-log4j-demo 项目中。
  • log4j-api-2.17.1.jar
  • log4j-core-2.17.1.jar
  • log4j-slf4j18-impl-2.17.1.jar
  1. 此外,我们还需要向 my-spring-log4j-demo 项目中导入一个 slf4j-api-xxx.jar ,但该依赖包的版本是有限制的。

此前,我们下载的 Log4j2 的依赖包中有一个 log4j-slf4j18-impl-2.17.1.jar,它是 Log4j2 提供的绑定到 SLF4J 的配置器。

Log4j2 提供了以下 2 个适配器:

  • log4j-slf4j-impl 应该与 SLF4J 1.7.x 版本或更早版本一起使用。
  • log4j-slf4j18-impl 应该与 SLF4J 1.8.x 版本或更高版本一起使用。

因此,我们向项目中引入的 slf4j-api-xxx.jar  必须为 1.8.x 及以上版本。这里我们以 slf4j-api-1.8.0-beta4.jar 为例,该 Jar 包我们可以使用浏览器访问的 slf4j-api 的 Maven 仓库进行下载,如下图。


图2:SLF4J API 下载页面

  1. 在 src 目录下,创建一个名为 log4j2.xml 的配置文件,配置内容如下。
xml
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!-- Configuration 后面的 status 用于设置 log4j2 自身内部的信息输出,可以不设置,当设置成 trace 时,可以看到 log4j2 内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的 appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义 logger,只有定义了 logger 并引入的 appender,appender 才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定 Logger,则会使用 root 作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>
  1. 在 net.biancheng.c 包下,创建一个名为 HelloLog4j 的 Java 类,代码如下。
java
package net.biancheng.c;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloLog4j {
    private static final Logger log = LoggerFactory.getLogger(HelloLog4j.class);
    private String message;
    public void setMessage(String message) {
        this.message = message;
    }
    public void getMessage() {
        log.info("消息为:" + message);
    }
}
  1. 在 src 目录下创建一个 Beans.xml,配置内容如下。
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   
    <bean id="helloLog4j" class="net.biancheng.c.HelloLog4j">
        <property name="message" value="Hello,Spring!"/>
    </bean>
</beans>
  1. 在 net.biancheng.c 包下,创建一个 MainApp 的类,代码如下。
java
package net.biancheng.c;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
    private static final Logger log = LoggerFactory.getLogger(MainApp.class);
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        log.info("正在从容器中获取 HelloLog4j 的 Bean");
        HelloLog4j obj = context.getBean("helloLog4j", HelloLog4j.class);
        obj.getMessage();
        log.info("代码执行完成!");
    }
}
  1. 执行 MainApp 中的 main() 方法,控制台输出如下。
2022-01-13 16:54:39.883 [main] INFO  net.biancheng.c.MainApp - 正在从容器中获取 HelloLog4j 的 Bean
2022-01-13 16:54:39.890 [main] INFO  net.biancheng.c.HelloLog4j - 消息为:Hello,Spring!
2022-01-13 16:54:39.891 [main] INFO  net.biancheng.c.MainApp - 代码执行完成!