Appearance
Spring 整合日志框架 Log4j2
对于一款软件而言,日志记录都是十分重要的。它不仅能够监控程序的运行情况,周期性的记录到文件中,还能够跟踪程序中代码的运行轨迹,向文件或控制台打印代码的调试信息。当程序出现错误时,日志记录可以帮助开发人员及时定位问题,因此对开发人员来说,日志记录更是尤为重要。
Spring 5 框架自带了通用的日志封装,但是我们依然可以整合其他的日志框架对日志进行记录,其中最广为人知的就是大名鼎鼎的 Log4j。
Log4j 是 Apache 提供的一款开源的强有力的 Java 日志记录工具。它可以通过配置文件灵活、细致地控制日志的生成过程,例如日志级别、日志的输出类型、日志的输出方式以及输出格式等。
Log4j 共有两个大版本,如下表所示。
版本 | 时间 | 说明 |
---|---|---|
Log4j 1.x | 1999 年至 2015 年 | 即我们常说的 Log4j, 它于 1999 年首次发布,就迅速成为有史以来最常用的日志框架。 2015 年 8 月 5 日,Apache Logging Services 宣布 Log4j 1.x 生命周期结束,其代码库不再发布更新,并鼓励用户升级到 Log4j 2.x。 |
Log4j 2.x | 2014 年至今 | 即我们常说的 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 的。
新建一个名为 my-spring-log4j-demo 的 Spring 项目,并将与 Spring 相关的 Jar 包导入到该项目中。
使用浏览器访问 Log4j2 官网,点击左侧导航栏中的 Download,跳转到 Log4j2 的下载页面。
图1:Log4j2 下载页面
- 我们根据自身操作系统的不同,选择不同的压缩包
- 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,因此这里就以此版本为例进行讲解。
- 对下载完成的压缩包进行解压,并将以下 3 个依赖包导入到 my-spring-log4j-demo 项目中。
- log4j-api-2.17.1.jar
- log4j-core-2.17.1.jar
- log4j-slf4j18-impl-2.17.1.jar
- 此外,我们还需要向 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 下载页面
- 在 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>
- 在 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);
}
}
- 在 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>
- 在 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("代码执行完成!");
}
}
- 执行 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 - 代码执行完成!