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中桥接器运行的原理是什么