认识Spring 中的日志

这篇文章你将了解到Spring生态中日志框架是如何演化集成的

Spring Boot 日志

众说周知,Spring Boot 统一了日志框架,统一使用Logback进行日志输出,不管内部依赖框架使用的何种日志,最终都以Logback输出,他为什么需要统一呢。

我们通过引入spring-boot-starter 依赖先来看看:

可见,通过spring-boot-starter引入了spring-boot、spring-boot-autoconfigure、spring-boot-starter-logging、jakarta.annotation-api、spring-core等;其中spring-boot-starter-logging主要引入日志相关的依赖,有logback-classic、log4j-to-slf4j、jul-to-slf4j,正因为有这些依赖spring boot 才能够统一日志框架,我们先看看这几个依赖的作用。

text 复制代码
logback-classic: logback的主要日志依赖  
log4j-to-slf4j:将lo4j日志桥接到了slf4j日志框架,spring 框架默认使用的,所以需要该依赖  
jul-to-slf4j:将jul日志桥接到了slf4j日志框架,tomcat框架默认使用的,jul 即Java Util Logging

正因为Spring Boot 使用到了Spring、Tomcat,但两者都各自使用了不同的日志框架,后面可能还有其他依赖框架,混乱的日志框架势必会对开发人员造成困扰。

这里我们看到两个依赖都桥接到了slf4j,那什么是slf4j?大部分人应该都知道slf4j是一种抽象日志框架,要能够输出日志,slf4j还需要绑定到具体的日志框架,比如logback-classic。那为什么会出来slf4j呢。

到目前为止Java生态有很多的日志框架:logback、log4j、log4j2、simpleLog、JUL等。这么多的日志框架,你想象一下,如果开始的时候你使用的JUL打印日志,随着新技术的发展又出来了log4j,另一波开发人员又引入了log4j,后面又出现了log4j2,多种日志框架充斥着系统,改配置就得改不同的文件,给维护带来很多麻烦。

Spring 日志

后来出现了Commons Logging(JCL),其通过统一的写法统一了框架日志,不需要根据不同的日志框架,不同的日志编码。

java 复制代码
 private Log log = LogFactory.getLog(CLASS.class);

通过如上编码,JCL会去寻找合适的日志框架,通过找到的日志框架打印日志。

但是随着时间的推移,JCL 在2014年后就没更新(2023年JCL又开始更新了一版1.3.0),后面被越来越多的人弃用,但是就如上面说的Spring 还是一直使用的JCL作为默认日志框架。

在Spring框架中有一个spring-jcl依赖,其中LogAdapter有一个静态方法块,用来选择要加载的Log API

java 复制代码
	private static final String LOG4J_SPI = "org.apache.logging.log4j.spi.ExtendedLogger";

	private static final String LOG4J_SLF4J_PROVIDER = "org.apache.logging.slf4j.SLF4JProvider";

	private static final String SLF4J_SPI = "org.slf4j.spi.LocationAwareLogger";

	private static final String SLF4J_API = "org.slf4j.Logger";


	private static final LogApi logApi;

static {
		if (isPresent(LOG4J_SPI)) {
			if (isPresent(LOG4J_SLF4J_PROVIDER) && isPresent(SLF4J_SPI)) {
				// log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI;
				// however, we still prefer Log4j over the plain SLF4J API since
				// the latter does not have location awareness support.
				logApi = LogApi.SLF4J_LAL;
			}
			else {
				// Use Log4j 2.x directly, including location awareness support
				logApi = LogApi.LOG4J;
			}
		}
		else if (isPresent(SLF4J_SPI)) {
			// Full SLF4J SPI including location awareness support
			logApi = LogApi.SLF4J_LAL;
		}
		else if (isPresent(SLF4J_API)) {
			// Minimal SLF4J API without location awareness support
			logApi = LogApi.SLF4J;
		}
		else {
			// java.util.logging as default
			logApi = LogApi.JUL;
		}
	}

如上,有一句话很有意思,
log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI; however, we still prefer Log4j over the plain SLF4J API since the latter does not have location awareness support.

如果存在log4j-to-slf4j 桥接器,那么就选择SLF4J ,但是我们还是更喜欢使用Log4j而不是SLF4J API,因为它没有位置感知支持。

LOG4J_SPI 存在于 log4j包中
LOG4J_SLF4J_PROVIDER 存在于log4j-to-slf4j中
SLF4J_SPI 存在于slf4j中
SLF4J_API存在于slf4j中

什么是位置感知?网上没有什么资料说这个问题?但我们可以问下大模型,看看怎么回答的。

好像也没错,SLF4J只是一个日志的抽象,没有具体实现,确实不能记录日志的发生位置~。

SLF4J

说回SLF4J,使用方式也跟JCL一样,只需要同样的代码,就能使用不同的日志框架。
Logger logger = LoggerFactory.getLogger(Wombat.class);

但是它比JCL更先进,只需要更换不同的绑定器,而不是将日志实现硬编码在代码中

SLF4J里面有还有两个概念,绑定器和桥接器。

绑定器:SLF4J绑定具体的日志实现框架,比如logback-classic是logback的绑定器https://slf4j.org/manual.html

桥接器:将以前的日志框架桥接到SLF4J中,使用SLF4J来确定具体的日志框架,更多的桥接器可以到官网中查看。https://slf4j.org/legacy.html

SLF4J起到了一个桥梁的工作,如同一个交通指挥员,指挥不同的日志框架如何进行转换,比JCL更灵活。


作者其他文章推荐:

基于Spring Boot 3.1.0 系列文章

  1. Spring Boot 源码阅读初始化环境搭建
  2. Spring Boot 框架整体启动流程详解
  3. Spring Boot 系统初始化器详解
  4. Spring Boot 监听器详解
  5. Spring Boot banner详解
  6. Spring Boot 属性配置解析
  7. Spring Boot 属性加载原理解析
  8. Spring Boot 异常报告器解析
  9. Spring Boot 3.x 自动配置详解
相关推荐
阿伟*rui33 分钟前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck3 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei3 小时前
java的类加载机制的学习
java·学习
昌sit!4 小时前
K8S node节点没有相应的pod镜像运行故障处理办法
云原生·容器·kubernetes
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~4 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616885 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7895 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java6 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet