slf4j中桥接器运行的原理是什么

  介绍

slf4j中桥接器运行的原理是什么?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

在日志框架slf4j中有一组项目,除了核心的slf4j-api之外,还有slf4j-log4j12, slf4j-jdk14等项目。这一类项目统称桥接器项目,针对不同的日志框架有不同的桥接器项目。

在使用logback日志框架时,并没有针对的桥接器,这是因为logback与slf4j是一个作者所写,在logback中直接实现了slf4j的SPI机制。

但如果使用其他日志框架,那么就必须要用到桥机器相关依赖。比如,当我们基于log4j使用slf4j时,除了需要引入log4j jar包的依赖,还需要引入slf4j的下面两个依赖:

& lt; dependency>   & lt; groupId> org.slf4j   & lt; artifactId> slf4j-api   & lt;/dependency>   & lt; dependency>   & lt; groupId> org.slf4j   & lt; artifactId> slf4j-log4j12   & lt;/dependency>

slf4j-api为核心依赖,必须引入,而slf4j-log4j12就是桥接器用来在slf4j和log4j之间进行过渡和封装。下面,我们就聊聊桥接器项目的核心实现。


要了解桥接器的运作,首先需要回顾一下slf4j的SPI机制。在我们通过LoggerFactory.getLogger (Foo.class);时,slf4j会通过SPI机制寻找并初始化SLF4JServiceProvider的实现类。

然后,通过SLF4JServiceProvider的实现类来获取日志相关的具体工厂类对象,进而进行日志功能的处理。先来看一下SLF4JServiceProvider的接口定义:

公共接口SLF4JServiceProvider {/* *
  *返回ILoggerFactory的实现类,用于LoggerFactory类的绑定
  */ILoggerFactory getLoggerFactory ();/* *
  *返回IMarkerFactory实例
  */IMarkerFactory getMarkerFactory ();/* *
  *返回MDCAdapter实例
  */MDCAdapter getMDCAdapter ();/* *
  *获取请求版本
  */字符串getRequesteApiVersion ();/* *
  *初始化,实现类中一般用于初始化ILoggerFactory等
  */无效的初始化();
  }

SLF4JServiceProvider接口是在slf4j-api中定义的,具体的实现类由其他日志框架来完成。但是像log4j (logback“敌对阵营”)是不会在框架内实现该接口的。那么,怎么办?

针对此问题,slf4j提供了slf4j-log4j12这类桥接器的过渡项目。在其中实现SLF4JServiceProvider接口,并对log4j日志框架接口进行封装,将日志记录器(slf4j)接收到的命令全部委托给记录器(log4j)去完成,在使用者无感知的情况下完成偷天换日。


理解了桥接器的存在价值及原理,下面就来看看slf4j-log4j12是如何实现这一功能的。

首先来看看核心实现类之一Log4j12ServiceProvider。它实现了SLF4JServiceProvider接口,主要功能就是完成接口中定义的相关工厂接口的实现。源代码如下:

 

该类的实现看起来很简单,构造方法中通过尝试使用log4j的水平。跟踪调用来验证log4j的版本是否符合要求.log4j1.2.12之前并没有水平。跟踪,所以会抛出异常,并打印日志信息。不得不赞叹作者在此处检查版本的巧妙用法。

而这里对接口中返回的实现类主要通过初始化()方法来实现的。这里我们重点看Log4jLoggerFactory类的实现。

公共最终类Log4jLoggerAdapter LegacyAbstractLogger实现LocationAwareLogger延伸,可序列化的{
  
  最后的瞬态org.apache.log4j。日志记录器;
  
  Log4jLoggerAdapter (org.apache.log4j。日志记录器){
  这一点。记录器=记录器;
  this.name=logger.getName ();
  traceCapable=isTraceCapable ();
  }
  
  @Override
  公共布尔isDebugEnabled () {
  返回logger.isDebugEnabled ();
  }
  
  
  @Override
  公共空间日志(标记标记,字符串callerFQCN, int,字符串味精,对象[]参数,Throwable t) {
  水平log4jLevel=toLog4jLevel(水平);
  NormalizedParameters np=NormalizedParameters。正常化(味精,参数,t);
  字符串formattedMessage=MessageFormatter.basicArrayFormat (np.getMessage (), np.getArguments ());
  记录器。日志(callerFQCN log4jLevel、formattedMessage np.getThrowable ());
  }
  
  公共空间日志(LoggingEvent事件){
  .toInt水平log4jLevel=toLog4jLevel (event.getLevel () ());
  如果(! logger.isEnabledFor (log4jLevel))
  返回;
  
  org.apache.log4j.spi。LoggingEvent log4jevent=toLog4jEvent(事件,log4jLevel);
  logger.callAppenders (log4jevent);
  
  }//省略其他方法
  }

slf4j中桥接器运行的原理是什么