SLF4J Spring Boot日志框架

JAVA日志框架

JAVA有好多优秀的日志框架,比如log4j、log4j2、logback、JUL(java.util.logging)、JCL(JAVA Common Logging)等等,logback是后起之秀,是Spring Boot默认日志框架。

今天文章的目标不是研究JAVA的这些日志框架,而是在应用中处于他们前面的日志门面SLF4J,以及初步了解一下Spring Boot的默认日志框架是在什么地方配置的、怎么替换Spring Boot默认的日志框架。

SLF4J

SFL4J,全名Simple Logging Facade for Java,意思是简单JAVA日志门面,是Facade设计模式的一个典型实现。

SFL4J本身并没有日志的任何实现,它只是一个日志门面,目的是为了让应用层能够简单的、方便的使用以上提到的各种不同的日志框架,在代码层不做任何改动的情况下,在最终部署的时候决定具体使用哪一个日志框架。冲这一点,SLF4J就非常NB,能允许程序员在编码的时候不考虑具体使用哪一个日志框架、部署的时候不需要修改一行代码、随意选择日志框架。而且,虽然不是很有必要,但是只要你高兴,应用运行的过程中你都可以随时切换日志框架,比如你刚开始选择log4j2,但是后来觉得不爽想要换成logback,只要你在开发的时候使用了SLF4J,你就可以任性地随时切换。

使用SLF4J

严格来说,SLF4J只需要一个包:slf4j-api-xxx.jar(xxx是版本号) 就可以使用,POM文件中引入:

    <dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></dependency>

之后:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class HelloWorld {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger(HelloWorld.class);logger.info("Hello World");}
}

应用classpath下有任何前述日志框架存在的情况下,以上代码中的日志打印语句就会根据日志框架的配置输出到控制台或者日志文件中了。

SLF4J API及jar包框架

上述案例可以发现,原则上来说,项目Pom文件引入slf4j-api之后,SLF4J就可以正常工作了,但是SLF4J可以正常工作,并不代表整个日志系统可以正常工作,因为SLF4J只是日志门面,需要绑定后端的日志框架之后,日志系统才能正常工作。

我们先看一下SLF4J官网对于SLF4J API的框架图:
在这里插入图片描述
可以看出,如果我们采用SLF4J本家的日志框架作为我们应用的日志框架的话,比如用logback的话,我们只需要slf4j-api.jar + logback相关的jar包就可以了,或者我们用slf4j自带的simple日志框架的话,也只需要slf4j-api.jar + slf4j-simple.jar。

但是如果用其他的三方日志框架,比如log4j、或者JUL的话,由于三方框架比如log4j早在SLF4J出现之前就已经占据JAVA日志的半壁江山了,所以早期版本的日志框架不可能适应后面才出现的SLF4J,所以只能SLF4J自己想办法来适应。

SLF4J给出的解决方案就是针对各日志框架的API:


slf4j-log4j12-2.0.10.jar: 为绑定log4j version 1.2,这是一个很古老的版本了,早已宣布寿终正寝了,但是考虑到有些老系统可能还在使用log4j 1.x,所以提供了这个jar包以便兼容。其实从SLF4J 1.7.35之后,slf4j-log4j模块的调用就已经在编译器直接导航到slf4j-reload4j的调用了,所以这个模块对于新版本的SLF4J来说几乎没用了。


slf4j-reload4j-2.0.10.jar:后期版本的SLF4J绑定log4j日志框架,同时需要reload4j.jar(log4j 1.2x之后的替代品)。


slf4j-jdk14-2.0.10.jar: SLF4J绑定JUL(java14之后的内置日志框架)日志框架,同时需要JDK14。


slf4j-nop-2.0.10.jar: 应用不绑定任何日志框架的情况下的SLF4J的默认NOP实现,啥也没干,只是在应用运行进行日志框架绑定的时候不报错。


slf4j-simple-2.0.10.jar: SLF4J自己实现的一个简单的、轻量级日志框架,应该没人用。


slf4j-jcl-2.0.10.jar: 绑定Apache Commons Logging。


logback-classic-xxx.jar: logback日志框架,同时需要logback-core-xxx.jar,可直接支持SLF4J。


将以上jar包放入或移除当前应用(或者通过pom文件)后,就可以轻而易举的实现日志框架的更换,不需要你动一行代码,这就是SLF4J的魔力。

不绑定

如果不引入任何日志框架、代码中又使用了SLF4J的话,会是什么情况?

如果版本是SLF4J 1.6.0 之前的版本,没有加载任何日志框架的情况下,SLF4J在绑定日志框架的时候会抛出异常:NoClassDefFoundError 。因为绑定日志框架的时候找不到org.slf4j.impl.StaticLoggerBinder类。

之后的、SLF4J2.0之前的版本,控制台会打印:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

SLF4J2.0以上,控制台会打印:

SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.

SLF4J 1.6.0之后,如果你的项目并没有加载日志框架,SLF4J提供了一个日志哑实现,叫no-operation (NOP) logger implementation,这个NOP其实就是个假把式,所有的日志打印操作都不会得到任何输出,NOP啥都不干。

桥接API

如果你的已有应用没有使用SLF4J、而是使用JCL或log4j等JAVA日志框架,SLF4J非常贴心的为你提供了两种方案、让你能够以最小代价将as-is系统的日志框架切换到SLF4J上来:

  1. Bridging legacy APIs:桥接API
  2. slf4j-migrator:代码迁移工具

桥接API图:
在这里插入图片描述
通过桥接API,允许你将既有系统的基于log4j、JCL、JUL等日志框架的系统迁移到SLF4J上来。原理是:jcl-over-slf4j.jar替换原有的commons-logging.jar,应用中对原来的JCL日志框架的调用接口都被替换成了jcl-over-slf4j.jar中的桥接接口,jcl-over-slf4j.jar桥接接口会将日志接口API重新定向到SLF4J中、从而纳入到SLF4J体系中来。

slf4j-migrator代码迁移工具是直接对你的代码动手术的,支持JCL、log4j、JUL的迁移:
在这里插入图片描述

Spring Boot默认日志框架

Spring Boot的默认日志框架是在spring-boot-starter中指定的,spring-boot-starter中包含了spring-boot-starter-logging:

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId><version>3.1.4</version><scope>compile</scope></dependency>

而spring-boot-starter-logging中引入了logback:

<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.11</version><scope>compile</scope></dependency>

所以,Spring Boot的默认日志框架是logback。

如果想要替换默认的日志框架,比如换成log4j2,首先需要在pom文件中加入依赖:

        <dependency><groupId>org.slf4j</groupId><artifactId>slf4j-reload4j</artifactId><version>2.0.10</version></dependency>

之后直接启动应用,发现:
在这里插入图片描述
这个信息是在应用系统的早期就打印出来了,说明日志框架的加载在Spring Boot启动过程中是比较早的。

然后,logback也可以正常工作了(代码中加入log可以检查一下底层日志框架到底是啥):

    public HelloWorldController(){log.info("---1=2---");log.info(log.getClass().getName());}

在这里插入图片描述
但是我们想要替换logback为log4j2的目标却没有实现!

原因在上面第一张图里已经说了,SLF4J在classpath下发现了两个provider(我们用的是SLF4J2.x版本,通过provider绑定底层日志框架)。

发现两个provider的话,SLF4J会依赖JVM随机绑定一个,我们测试的这个案例是绑定了logback。

怎么能让它绑定log4j呢?

其实通过SLF4J的源码发现了一种方法,就是指定环境变量:
在这里插入图片描述

System property for explicitly setting the provider class. If set and the provider could be instantiated, then the service loading mechanism will be bypassed.
Since:2.0.9

如果指定了这个环境变量,SLF4J的加载机制就会被跳过而直接加载指定的provider,比如:
在这里插入图片描述
从代码看这个设置也是应该能生效的:

static List<SLF4JServiceProvider> findServiceProviders() {List<SLF4JServiceProvider> providerList = new ArrayList<>();// retain behaviour similar to that of 1.7 series and earlier. More specifically, use the class loader that// loaded the present class to search for servicesfinal ClassLoader classLoaderOfLoggerFactory = LoggerFactory.class.getClassLoader();SLF4JServiceProvider explicitProvider = loadExplicitlySpecified(classLoaderOfLoggerFactory);if(explicitProvider != null) {providerList.add(explicitProvider);return providerList;}

loadExplicitlySpecified方法:

static SLF4JServiceProvider loadExplicitlySpecified(ClassLoader classLoader) {String explicitlySpecified = System.getProperty(PROVIDER_PROPERTY_KEY);if (null == explicitlySpecified || explicitlySpecified.isEmpty()) {return null;}try {String message = String.format("Attempting to load provider \"%s\" specified via \"%s\" system property", explicitlySpecified, PROVIDER_PROPERTY_KEY);Util.report(message);Class<?> clazz = classLoader.loadClass(explicitlySpecified);Constructor<?> constructor = clazz.getConstructor();Object provider = constructor.newInstance();return (SLF4JServiceProvider) provider;} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {String message = String.format("Failed to instantiate the specified SLF4JServiceProvider (%s)", explicitlySpecified);Util.report(message, e);return null;} catch (ClassCastException e) {String message = String.format("Specified SLF4JServiceProvider (%s) does not implement SLF4JServiceProvider interface", explicitlySpecified);Util.report(message, e);return null;}}

如果指定了这个系统参数的话,就直接通过classloader实例化这个provider…但是确实没有测试成功,暂时没找到原因。

我们还有另外一个启用log4j2、停用logback的方案,pom文件排除logback:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId></exclusion></exclusions></dependency>

之后刷新pom,发现logback的引用已经消失了。
刷新前:
在这里插入图片描述
刷新后:
在这里插入图片描述

启动应用:
在这里插入图片描述
就会发现Spring Boot项目使用log4j就没有用logback那么舒服了,log4j是需要配置的。随便放一个log4j.properties配置文件就可以正常工作了。

@Slf4j注解

@Slf4j是lombok的一个注解,所以你就能知道他其实没啥,语法糖而已,帮着你在当前类生成一个:

private static final org.slf4j.Logger log =org.slf4j.LoggerFactory.getLogger(Youclass.class);

Ohhh…OK

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

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

相关文章

oracle19c容器数据库rman备份特性-----性能优化(三)

目录 冗余备份片 1.备份的时候指定 2.rman配置中设定 归档备份&#xff08;将备份集保留&#xff09; 二级备份&#xff08;将备份文件保留&#xff09; 1.备份闪回恢复区的恢复文件 2.备份所有恢复文件 recovery catalog database 1.創建recovery catalog 2.创建VPC…

zabbix-proxy代理安装及其他监控方式

zabbix-proxy代理安装及其他监控方式 安装zabbix-proxyserver端配置zabbix-proxy配置被监控的agent安装中问题解决监控网络设备JMX和IPMI监控方式 zabbix-proxy的安装&#xff0c;至少需要准备三台机器&#xff0c;一台安装服务端&#xff0c;一台安装agent端&#xff0c;这里就…

《网络是怎样连接的》2.3节图表(自用)

图4.1&#xff1a;TCP拆分数据与ACK号 图4.2&#xff1a;连接阶段与通信阶段ACK号与序号的交互过程 首先&#xff0c;客户端在连接时需要计算出与从客户端到服务器方向通信相关的序号初始值&#xff0c;并将这个值发送给服务器&#xff08;①&#xff09;。 接下来&#xff0c…

在k8s集群中部署多nginx-ingress

关于ingress的介绍&#xff0c;前面已经详细讲过了&#xff0c;参考ingress-nginx详解和部署方案。本案例ingress的部署使用deploymentLB的方式。 参考链接&#xff1a; 多个ingress部署 文章目录 1. 下载ingress的文件2. 文件资源分析3. 部署ingress3.1 部署第一套ingress3.1…

C# 反射的乌云,MethodInfo的Json序列化参数入参问题

文章目录 前言直接运行MethodInfo运行结果 Json解决ParamterInfo实例化运行结果无法实例化问题部分参数的问题 Json反序列化 经过长达一天的研究&#xff0c;我终于完全的解决的了实战思路方法测试用例运行测试运行结果 代码总结总结 前言 我上篇文章已经基本解决了反射的基本…

众和策略:沪指跌0.91%险守2900点,半导体、金融等板块走低

8日早盘&#xff0c;两市股指低开低走&#xff0c;沪指一度失守2900点&#xff0c;深成指、创业板指跌约1%&#xff0c;科创50指数创前史新低。 到午间收盘&#xff0c;沪指跌0.91%报2902.4点&#xff0c;深成指跌1.17%&#xff0c;创业板指跌0.99%&#xff0c;科创50指数跌超…

如何通过PreMaint状态监测发现设备故障:以振动监测为例

在现代工业环境中&#xff0c;设备的健康状况对于维持生产效率至关重要。计划外停机可能导致巨大的成本损失&#xff0c;因此采用先进的监测技术成为预防性维护的核心策略之一。其中&#xff0c;振动监测作为一种早期故障检测手段&#xff0c;通过PreMaint状态监测系统的引入&a…

《网络是怎样连接的》2.5节图表(自用)

图5.1&#xff1a;ip包结构 图5.2&#xff1a;ip网络包的传输方式 1.以太网的部分也可以替换成其他的东西&#xff0c;例如无线局域网、ADSL、FTTH等&#xff0c;它们都可以替代以太网的角色帮助IP协议来传输网络包 2.根据ARP协议&#xff0c;客户端可以根据ip地址得到下一个路…

最新最简操作系统期末复习(考前速过)

操作系统复习 第一章&#xff08;操作系统引论&#xff09;计算机操作系统包括&#xff1a;操作系统的目标&#xff1a;操作系统的作用&#xff1a;未配置操作系统的计算机系统&#xff1a;单道批处理系统&#xff1a;缺点&#xff1a; 多道批处理系统&#xff1a;优点&#xf…

国际版WPS Office18.6.0

​【应用名称】&#xff1a;WPS Office 【适用平台】&#xff1a;Android 【软件标签】&#xff1a;WPS 【应用版本】&#xff1a;18.5.4 → 18.6.0 【应用大小】&#xff1a;160MB 【软件说明】&#xff1a;WPS Office是使用人数最多的移动办公软件。它具有独有手机阅读…

TypeScript基础

ts学习 目录概述需求&#xff1a; 设计思路实现思路分析1.TypeScript 基础类型2.TypeScript 变量声明3.TypeScript 接口4.TypeScript 类5.TypeScript 函数5.TypeScript 泛型5.TypeScript 枚举TypeScript 类型推论TypeScript 类型兼容性TypeScript 高级类型TypeScript 迭代器和生…

RoadMap8:C++中类的封装、继承、多态与构造函数

摘要&#xff1a;在本章中涉及C最核心的内容&#xff0c;本文以C中两种基础的衍生数据结构&#xff1a;结构体和类作为引子&#xff0c;从C的封装、继承与多态三大特性全面讲述如何在类这种数据结构进行体现。在封装中&#xff0c;我们讲解了类和结构体的相似性&#xff1b;在继…

自带恒压恒流环路的降压型单片车充专用芯片

一、基本概述 XL2009是一款高效降压型DC-DC转换器&#xff0c;固定180KHz开关频率&#xff0c;可以提供最高2.5A输出电流能力&#xff0c;具有低纹波&#xff0c;出色的线性调整率与负载调整率特点。XL2009内置固定频率振荡器与频率补偿电路&#xff0c;简化了电路设计。 PWM …

Docker(八)Python+旧版本chrome+selenium+oss2+fastapi镜像制作

目录 一、背景二、能力三、核心流程图四、制作镜像1.资源清单2.Dockerfile3.制作镜像 五、启动测试 一、背景 近几年我们线下的创业团队已从零到一开发过好几个小程序项目&#xff0c;都是和体育相关。其中生成海报分享图片好像都是不可或缺的功能。之前的项目老板给的时间都比…

从零学算法17

17.给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits “23” 输出&#xff1a;[…

Java进击框架:Spring-Web(八)

Java进击框架&#xff1a;Spring-Web&#xff08;八&#xff09; 前言DispatcherServlet拦截器异常视图解析重定向转发 语言环境日志 过滤器带注释的控制器声明映射请求其它注解验证 功能性端点URI Links异步请求CORSHTTP缓存视图技术MVC配置其他Web框架 前言 Spring Web MVC是…

519基于单片机的自动切割流程控制系统

基于单片机的自动切割流程控制系统[proteus仿真] 自动切割流程控制系统这个题目算是课程设计和毕业设计中常见的题目了&#xff0c;本期是一个基于单片机的自动切割流程控制系统 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】&#xff0c;赞赏任意文章 2&…

无人驾驶卡尔曼滤波

无人驾驶卡尔曼滤波&#xff08;行人检测&#xff09; x k a x k − 1 w k x_k ax_{k-1} w_k xk​axk−1​wk​ w k w_k wk​&#xff1a;过程噪声 状态估计 估计飞行器状态&#xff08;高度&#xff09; x k z k − v k x_k z_k - v_k xk​zk​−vk​ 卡尔曼滤波通…

了解什么是UV纹理?

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 什么是UV&#xff1f; UV 是与几何图形的顶点信息相对应的二维纹理坐…

CentOS找回root密码

很悲伤&#xff0c;你忘记了root密码。。。 那就来重置它吧~ 1、在启动时选择操作系统&#xff1a;在引导过程中&#xff0c;选择CentOS操作系统并按下键盘上的任意键来停止引导。 2、 进入编辑模式&#xff1a;在启动菜单中&#xff0c;找到并选择要编辑的CentOS条目&…