slf4j日志框架绑定机制
Posted yeyang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了slf4j日志框架绑定机制相关的知识,希望对你有一定的参考价值。
一、环境搭建
我们以log4j为例,探寻slf4j与log4j的绑定过程。
1.Java类
public class Slf4jBind { public static void main(String[] args) { Logger LOGGER = LoggerFactory.getLogger(Slf4jBind.class); LOGGER.info("slf4j hello world"); } }
2.log4j.properties文件
来自https://docs.oracle.com/cd/E29578_01/webhelp/cas_webcrawler/src/cwcg_config_log4j_file.html
log4j.rootLogger=ERROR,stdout log4j.logger.com.endeca=INFO # Logger for crawl metrics log4j.logger.com.endeca.itl.web.metrics=INFO ? log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%p %d{ISO8601} %r %c [%t] %m%n
3.Maven的pom.xml中添加如下依赖
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.4</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency>
其中,slf4j-api定义接口的包。
slf4j-log4j12为slf4j与logj之间的桥接包。
log4j为log4j的具体实现包。
4.单步跟踪
在main函数处打断点,debug模式下单步跟踪即可
二、slf4j绑定log4j流程
main函数中调用LoggerFactory.getLogger时,将依次执行下面的函数。
slf4j对LoggerFactroy的说明如下:
LoggerFactory是为各个日志API生成Logger的帮助类。
如log4j,logback,jdk 1.4 logging,也支持NOPLogger,SimpleLogger。
LoggerFactory内部封装了ILoggerFactory,具体的ILoggerFactory与LoggerFactory在编译期(complile time)绑定。
public static Logger getLogger(Class clazz) { return getLogger(clazz.getName()); } public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); } ? / * ILoggerFactory instance is bound with this class at compile time. * * @return the ILoggerFactory instance in use */ public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITILIZATION; performInitialization(); ? } switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITILIZATION: return StaticLoggerBinder.getSingleton().getLoggerFactory(); case NOP_FALLBACK_INITILIZATION: return NOP_FALLBACK_FACTORY; case FAILED_INITILIZATION: throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); case ONGOING_INITILIZATION: // support re-entrant behavior. // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 return TEMP_FACTORY; } throw new IllegalStateException("Unreachable code"); }
private final static void performInitialization() { //对具体的日志框架实现是否仅有一个进行check singleImplementationSanityCheck(); //与具体的日志框架绑定 bind(); if (INITIALIZATION_STATE == SUCCESSFUL_INITILIZATION) { //版本依赖兼容性check versionSanityCheck(); } }
1.对具体的日志框架实现是否仅有一个进行check。
1).判断classpath下是否有多个org/slf4j/impl/StaticLoggerBinder.class
2).如果有多个,将提示有多个SLF4J的绑定包。
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"; ? private static void singleImplementationSanityCheck() { try { ClassLoader loggerFactoryClassLoader = LoggerFactory.class .getClassLoader(); Enumeration paths; if (loggerFactoryClassLoader == null) { paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH); } else { paths = loggerFactoryClassLoader .getResources(STATIC_LOGGER_BINDER_PATH); } // use Set instead of list in order to deal with bug #138 // LinkedHashSet appropriate here because it preserves insertion order during iteration Set implementationSet = new LinkedHashSet(); while (paths.hasMoreElements()) { URL path = (URL) paths.nextElement(); implementationSet.add(path); } if (implementationSet.size() > 1) { Util.report("Class path contains multiple SLF4J bindings."); Iterator iterator = implementationSet.iterator(); while(iterator.hasNext()) { URL path = (URL) iterator.next(); Util.report("Found binding in [" + path + "]"); } Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation."); } } catch (IOException ioe) { Util.report("Error getting resources from path", ioe); } }
2.绑定具体的日志框架
根据找到的org/slf4j/impl/StaticLoggerBinder.class,执行StaticLoggerBinder.getSingleton()进行绑定。
private final static void bind() { try { // the next line does the binding StaticLoggerBinder.getSingleton();//绑定 INITIALIZATION_STATE = SUCCESSFUL_INITILIZATION; emitSubstituteLoggerWarning(); } catch (NoClassDefFoundError ncde) { String msg = ncde.getMessage(); if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { INITIALIZATION_STATE = NOP_FALLBACK_INITILIZATION; Util .report("Failed to load class "org.slf4j.impl.StaticLoggerBinder"."); Util.report("Defaulting to no-operation (NOP) logger implementation"); Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details."); } else { failedBinding(ncde); throw ncde; } } catch(java.lang.NoSuchMethodError nsme) { String msg = nsme.getMessage(); if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) { INITIALIZATION_STATE = FAILED_INITILIZATION; Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding."); Util.report("Your binding is version 1.5.5 or earlier."); Util.report("Upgrade your binding to version 1.6.x. or 2.0.x"); } throw nsme; } catch (Exception e) { failedBinding(e); throw new IllegalStateException("Unexpected initialization failure", e); } }
因为具体的日志框架为log4j,StaticLoggerBinder返回的为Log4j的LoggerFactory。
private final ILoggerFactory loggerFactory; ? private StaticLoggerBinder() { loggerFactory = new Log4jLoggerFactory(); try { Level level = Level.TRACE; } catch (NoSuchFieldError nsfe) { Util .report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version"); } }
经过以上步骤,slf4j将于具体的日志框架log4j绑定。
如下所示,ILoggerFactory实际返回类型为Log4jLoggerFactory。
并调用Log4jLoggerFactory中的getLogger方法返回Log4jLogger用于log写入。
以上是关于slf4j日志框架绑定机制的主要内容,如果未能解决你的问题,请参考以下文章
Java日志框架 -- SLF4J日志门面(入门案例SLF4J优点SLF4J日志绑定SL4J桥接旧的日志框架)
Java日志框架 -- SLF4J日志门面(入门案例SLF4J优点SLF4J日志绑定SL4J桥接旧的日志框架)
Java日志框架 -- SLF4J日志门面(入门案例SLF4J优点SLF4J日志绑定SL4J桥接旧的日志框架)