SLF4J堕担,即簡單日志門面(Simple Logging Facade for Java)欢伏,不是具體的日志解決方案匿垄,它只服務(wù)于各種各樣的日志系統(tǒng)。按照官方的說法虎忌,SLF4J是一個用于日志系統(tǒng)的簡單Facade泡徙,允許最終用戶在部署其應(yīng)用時使用其所希望的日志System,
Logger log = LoggerFactory.getLogger(getClass());
LoggerFactory 是一個final 類 也是一個日志工廠類 生產(chǎn) Logger 對象,看看getLogger 方法
public static Logger getLogger(Class clazz) {
return getLogger(clazz.getName());
}
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
public static ILoggerFactory getILoggerFactory() {
//假如是未初始化狀態(tài)
if (INITIALIZATION_STATE == UNINITIALIZED) {
//初始化狀態(tài)為 正在進(jìn)行中
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
//進(jìn)入performIntialization 方法初始化膜蠢!
performInitialization();
}
switch (INITIALIZATION_STATE) {
//假如初始化成功
case SUCCESSFUL_INITIALIZATION:
//獲取具體的日志工廠對象
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION:
// 返回NOPLoggerFactory 日志工廠
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
//初始化失敗 拋出異常
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// 返回 SubstituteLoggerFactory 日志工廠
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
private final static void performInitialization() {
//綁定一個具體的日志實現(xiàn)
bind();
if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
//檢查日志的版本
versionSanityCheck();
}
}
private final static void bind() {
try {
//尋找日志綁定實現(xiàn)類堪藐,如果找不到或者指定的方法不存在,都會報錯提示,實現(xiàn)類可能有多個挑围,
//因此用Set集合
Set staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
//報告打印
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
// 測試是否存在 getSingleton 方法
StaticLoggerBinder.getSingleton();
// 設(shè)置初始化狀態(tài)礁竞,初始化成功
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
//報告打印實際的綁定類型
reportActualBinding(staticLoggerBinderPathSet);
emitSubstituteLoggerWarning();
//如果找不到指定的類
} 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;
}
//如果找不到指定的方法 也就是 getSingleton 方法
} catch (java.lang.NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
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);
}
}
尋找綁定實現(xiàn)類
private static Set findPossibleStaticLoggerBinderPathSet() {
Set staticLoggerBinderPathSet = new LinkedHashSet();
try {
//獲取LoggerFactory的類加載器
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration paths;
//假如LoggerFactory的類加載器為空
if (loggerFactoryClassLoader == null) {
//如果獲取不到類加載器則說明是系統(tǒng)加載器,那么在系統(tǒng)路徑下獲取該資源文件
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 ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
通過以上代碼 找到了默認(rèn)的 日志綁定實現(xiàn)類 StaticLoggerBinder模捂,在通過該綁定類來獲取Log4jLoggerFactory 具體的日志工廠對象
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
//單例
public static final StaticLoggerBinder getSingleton() {
return SINGLETON;
}
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");
}
}
// 獲取 Log4jLoggerFactory 類 對象
public ILoggerFactory getLoggerFactory() {
return loggerFactory;
}
在看看 Log4jLoggerFactory 類的 實現(xiàn),Log4jLoggerFactory類 是對 ILoggerFactory接口的實現(xiàn)
ILoggerFactory 只定義了一個方法
public interface ILoggerFactory {
public Logger getLogger(String name);
}
public class Log4jLoggerFactory implements ILoggerFactory {
ConcurrentMap<String, Logger> loggerMap;
public Log4jLoggerFactory() {
loggerMap = new ConcurrentHashMap<String, Logger>();
}
public Logger getLogger(String name) {
//查看是否存在key 為 name 的 Logger 對象
Logger slf4jLogger = loggerMap.get(name);
if (slf4jLogger != null) {
return slf4jLogger;
} else {
//這才是具體的日志實現(xiàn)
org.apache.log4j.Logger log4jLogger;
//獲取log4jLogger 類對象
if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
log4jLogger = LogManager.getRootLogger();
else
log4jLogger = LogManager.getLogger(name);
//Log4jLoggerAdapter 是一個適配器類 用于適配Logger 接口
//因為 Log4jLoggerAdapter 繼承自 MarkerIgnoringBase 類
//而 MarkerIgnoringBase 類 又實現(xiàn)了 Logger 接口
// 所有的底層都是 log4jLogger 去實現(xiàn)的
Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
return oldInstance == null ? newInstance : oldInstance;
}
}
}
總結(jié)
Slf4j 主要用到了 JVM類加載機(jī)制 門面設(shè)計模式 適配器設(shè)計模式
簡單的說下它的原理蜘矢,就是通過工廠類狂男,提供一個用戶的接口!用戶可以通過這個外觀接口品腹,直接使用API實現(xiàn)日志的記錄岖食。而后面的具體實現(xiàn)由Slf4j來尋找加載.尋找的過程,就是通過類加載加載那個叫org/slf4j/impl/StaticLoggerBinder.class的文件舞吭,只要實現(xiàn)了這個文件的日志實現(xiàn)系統(tǒng)县耽,都可以作為一種實現(xiàn)方式。如果找到很多種方式镣典,那么就尋找一種默認(rèn)的方式