ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Slf4j原理解析

2022-01-18 22:01:28  阅读:206  来源: 互联网

标签:LoggerFactory 框架 slf4j 接口 Slf4j api 原理 日志 解析


一、介绍

Simple Logging Facade for Java(SLF4J)用作各种日志框架(例如java.util.logging,logback,log4j)的简单外观或抽象,允许最终用户在部署时插入所需的日志框架。

要切换日志框架,只需替换类路径上的slf4j绑定。 例如,要从java.util.logging切换到log4j,只需将slf4j-jdk14-1.8.0-beta2.jar替换为slf4j-log4j12-1.8.0-beta2.jar

SLF4J不依赖于任何特殊的类装载机制。 实际上,每个SLF4J绑定在编译时都是硬连线的,以使用一个且只有一个特定的日志记录框架。 例如,slf4j-log4j12-1.8.0-beta2.jar绑定在编译时绑定以使用log4j。 在您的代码中,除了slf4j-api-1.8.0-beta2.jar之外,您只需将您选择的一个且只有一个绑定放到相应的类路径位置。 不要在类路径上放置多个绑定。

因此,slf4j 就是众多日志接口的集合,他不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。具体有哪些接口,全部都定义在slf4j-api中。查看slf4j-api源码就可以发现,里面除了public final class LoggerFactory类之外,都是接口定义。因此,slf4j-api本质就是一个接口定义。

总之,Slf4j更好的兼容了各种具体日志实现的框架,如图:

应用application通过slf4j桥接器桥接不同的日志框架,通过slf4j api进行日志打印的操作。

从本质上来讲slf4j主要是通过不同的桥接器对接了不同的日志框架,具体的日志打印仍然由日志框架去实现。

二、SLF4J的工作流程

SLF4J通过slf4j-api访问桥接器slf4j-log4j12生成LoggerFactory对象,通过LoggerFactory对象的getLogger返回桥接器的LoggerAdapter对象,通过LoggerAdapter的info方法输出日志,整体的执行过程如下图。

 

  1. SLF4J的工作流程核心包含获取Logger对象流程和打印日志流程。
  2. SLFTJ通过slf4j-api调用log4j桥接器slf4j-log4j12的StaticLoggerBinder生成LoggerFactory对象。
  3. SLFTJ通过slf4j-api的getLogger方法访问桥接器生产Logger对象。
  4. SLFTJ通过桥接器的Logger对象实现日志的格式化和打印

三、SLF4J的流程源码

1.SPI

使用serviceLoader,实现SPI,加载类路径下实现了slf4j接口的所有日志框架实现。这些日志框架实现实现org.slg4j包下的工厂接口及类接口。

Java SPI机制:ServiceLoader实现原理及应用剖析

2.LoggerFactory

使用门面模式,从实现了slf4j接口的日志框架中找到可以用的框架,找不到,则使用helpers包下【默认的接口实现】

3.Logger

实现日志输出的核心类

4.Marker

给日志打标,可用于日志过滤/筛选等

5.MDC ( Mapped Diagnostic Contexts ) 

MDC ( Mapped Diagnostic Contexts ) 有了日志之后,我们就可以追踪各种线上问题。但是,在分布式系统中,各种无关日志穿行其中,导致我们可能无法直接定位整个操作流程。因此,我们可能需要对一个用户的操作流程进行归类标记,比如使用线程+时间戳,或者用户身份标识等;如此,我们可以从大量日志信息中grep出某个用户的操作流程,或者某个时间的流转记录。其目的是为了便于我们诊断线上问题而出现的方法工具类。虽然,Slf4j 是用来适配其他的日志具体实现包的,但是针对 MDC功能,目前只有logback 以及 log4j 支持。

5.二进制兼容性(Binary backward compatibility)

二进制兼容的两个库可以相互替换,而不会引发任何的链接错误(LinkageError)。

这里LocationAwareLogger 是 api包下的一个类,DEBUG_INT等日志等级常量本可以放在EventConstants中,但是为了保证二进制兼容心【新版本库可以在使用代码不编译的情况下代替旧版本库】,将这些日志常量定义在LocationAwareLogger 接口中,保证各个实现类都包含这些常量,提醒相关开发人员在进行新版本开发时不要擅自更改这些常量。

为何需要关心二进制兼容性?

6.门面模式

先从概念上了解一下:门面模式(Facade Pattern),外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。门面模式又称为外观模式,它是一种对象结构型模式。 为了具体说明这个门面模式是如何工作的,这里写了一个简单例子,让我们根据这个例子看看这里面的学问。

上面所说的“高层接口”指的就是slf4j,而子系统则是诸如logging, logback and log4j这种具体实现。

7.装饰器模式-SubstituteLoggerFactory

在case ONGOING_INITIALIZATION:的情况下,此时是因为其他线程已经在初始化LoggerFactory了,为了避免阻塞等待初始化,当其他线程发现有线程已经在初始化时则会返回一个SUBST_FACTORY,该对象是SubstituteLoggerFactory类型,在其上调用getLogger会返回一个临时的SubstituteLogger。

SubstituteLogger是一个装饰者类,所有方法的调用都会交给真正的Logger对象进行处理,如方法所示:

delegate方法的处理也很容易理解,当delegate为空时,则判断createdPostInitialization是否为真,为真则返回NOP_LOGGER,否则通过getEventRecordingLogger返回一个EventRecodingLogger,该Logger会将所有日志包装成事件,放到对应的队列中缓存。

_delegate对象在另一个线程初始化LoggerFactory完成之后,调用org.slf4j.LoggerFactory#fixSubstituteLoggers方法进行注入。

而之前缓存的日志事件也会由该初始化线程调用org.slf4j.LoggerFactory的replayEvents方法由真正的Logger进行重放。

这个设计点使得多线程在初始化LoggerFactory的时候不会阻塞对方,并且也不会影响在初始化结束之前的日志记录。

标签:LoggerFactory,框架,slf4j,接口,Slf4j,api,原理,日志,解析
来源: https://blog.csdn.net/qq_39326472/article/details/122569587

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有