閱讀源碼以前,首先提幾個問題html
這段文字摘錄自官網:In your code, in addition to slf4j-api-1.8.0-beta2.jar, you simply drop one and only one binding of your choice onto the appropriate class path location. Do not place more than one binding on your class path.java
帶着上面的兩個問題看下源碼apache
// org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar!/org/slf4j/LoggerFactory.class
private static final void bind() {
// ...
if (!isAndroid()) {
// 查找日誌框架的綁定
staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
}
// ...
}
複製代碼
// org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar!/org/slf4j/LoggerFactory.class
static Set<URL> findPossibleStaticLoggerBinderPathSet() {
LinkedHashSet staticLoggerBinderPathSet = new LinkedHashSet();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration paths;
/* * 經過ClassLoader或者loggerFactoryClassLoader來獲取Resources * "STATIC_LOGGER_BINDER_PATH"的值在文件一開始已經定義過了 * private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"; */
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while(paths.hasMoreElements()) {
URL path = (URL)paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException var4) {
Util.report("Error getting resources from path", var4);
}
return staticLoggerBinderPathSet;
}
複製代碼
// org/apache/logging/log4j/log4j-slf4j-impl/2.11.1/log4j-slf4j-impl-2.11.1.jar!/org/slf4j/impl/StaticLoggerBinder.class
// 這裏的包名定義爲org.slf4j.impl,使得上述第2步的Class Loader能夠加載到這個類
package org.slf4j.impl;
public final class StaticLoggerBinder implements LoggerFactoryBinder {
// log4j init...
}
複製代碼
// ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class
// 這裏的包名定義爲org.slf4j.impl,使得上述第2步的Class Loader能夠加載到這個類
package org.slf4j.impl;
public class StaticLoggerBinder implements LoggerFactoryBinder {
// logback init...
}
複製代碼
// org/slf4j/slf4j-jcl/1.7.25/slf4j-jcl-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class
// 這裏的包名定義爲org.slf4j.impl,使得上述第2步的Class Loader能夠加載到這個類
package org.slf4j.impl;
public class StaticLoggerBinder implements LoggerFactoryBinder {
// jcl init...
}
複製代碼
SLF4J經過加載各個底層日誌框架橋接庫的org/slf4j/impl/StaticLoggerBinder.class來加載初始化對應的日誌框架。api
slf4j-api中的LoggerFactory中,在上述第2步返回staticLoggerBinderPathSet後,會立馬調用 reportMultipleBindingAmbiguity(staticLoggerBinderPathSet)方法來檢測是否有多個binding。若是有多個binding,就輸出錯誤信息"Class path contains multiple SLF4J bindings."app
private static void reportMultipleBindingAmbiguity(Set<URL> binderPathSet) {
if (isAmbiguousStaticLoggerBinderPathSet(binderPathSet)) {
Util.report("Class path contains multiple SLF4J bindings.");
Iterator i$ = binderPathSet.iterator();
while(i$.hasNext()) {
URL path = (URL)i$.next();
Util.report("Found binding in [" + path + "]");
}
Util.report("See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.");
}
}
複製代碼
代碼中使用SLF4J來記錄日誌,能夠任意切換底層日誌框架而不須要修改代碼,只須要更改依賴以及日誌配置文件便可。框架