(1). 概述
对于slf4j一直都是偏于简单的使用,而,我个人性格是偏向于:知其然,知其所以然,这个世界,人都是一直处理变化中,而技术也会不断的迭代来着的.
(2). slf4j入口在哪?
slf4j源码的入口在:LoggerFactory类上(注意:此次分析的源码为1.7,1.8之后有一些新的变化.)
package org.slf4j;
public final class LoggerFactory {
// 1. getLogger通过:ILoggerFactory创建:Logger
// 典型的工厂模式
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
} // end getLogger
}
(3). 获取日志工厂(getILoggerFactory)
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
// *****************************************************************
// 准备初始化
// *****************************************************************
performInitialization();
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
// *****************************************************************
// 很好奇为什么是通过静态创建工厂?
// 细细去剖析:当slf4j在打包(mvn)时,会排除该类:StaticLoggerBinder
// 而logback包里会写这样一个类,这也太粗爆了吧!
// 另一个疑问来了:为什么不用SPI?切换源码到最新分支时,发现在1.8是通过SPI来做的了.
// *****************************************************************
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION:
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// support re-entrant behavior.
// See also http://jira.qos.ch/browse/SLF4J-97
return SUBST_FACTORY;
}
throw new IllegalStateException("Unreachable code");
} // end getILoggerFactory
(4). performInitialization
private final static void performInitialization() {
bind();
if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
versionSanityCheck();
}
}
(5). bind
private final static void bind() {
try {
Set<URL> staticLoggerBinderPathSet = null;
if (!isAndroid()) {
// ***************************************************************
// 通过ClassLoader加载:org/slf4j/impl/StaticLoggerBinder.class
// ***************************************************************
staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
}
// the next line does the binding
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(staticLoggerBinderPathSet);
} catch (NoClassDefFoundError ncde) {
String msg = ncde.getMessage();
if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
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.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
INITIALIZATION_STATE = FAILED_INITIALIZATION;
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.");
}
throw nsme;
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
} finally {
postBindCleanUp();
}
} // end bind
(6). findPossibleStaticLoggerBinderPathSet
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
static Set<URL> findPossibleStaticLoggerBinderPathSet() {
Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration<URL> paths;
if (loggerFactoryClassLoader == null) {
// 通过ClassLoader加载:"org/slf4j/impl/StaticLoggerBinder.class"
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
// 通过ClassLoader加载:"org/slf4j/impl/StaticLoggerBinder.class"
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
} // end findPossibleStaticLoggerBinderPathSet
(7). 总结
slf4j的设计有点粗爆,也就是说那些slf4j的实现(或者桥接jar),肯定会存在org/slf4j/impl/StaticLoggerBinder类,瞬间就不想看下去了.