翻了一下百度和官網。這么介紹slf4j。
slf4j 全稱 Simple Logging Facade for Java,是日志框架的一種抽象,那么也就是說 slf4j 是不能單獨使用的必須要有其他實現日志框架來配合使用,並且如果要啟用slf4j框架要導入slf4j-api-xxx.jar 這個包, 這個包是slf4j 實現各種支持的日志框架的包。比如log4j、log4j2、logback等。 slf4j也已經支持這幾種日志組件。
這里拿slf4j 和logback的整合使用為例,先來看依賴關系
簡單的從淺層源碼來查找依賴關系
通常我們在java類中使用日志要先拿到Logger,如:
private static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
我們來看getLogger方法的代碼,注意 getLogger 這個靜態方法是屬於 slf4j-api-xxx.jar的org.slf4j包下的。
public static Logger getLogger(Class<?> clazz) { Logger logger = getLogger(clazz.getName()); if (DETECT_LOGGER_NAME_MISMATCH) { Class<?> autoComputedCallingClass = Util.getCallingClass(); if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) { Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName())); Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation"); } } return logger; }
繼續看方法第一行 getLogger的代碼
public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); }
繼續看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: 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"); }
注意看:StaticLoggerBinder.getSingleton().getLoggerFactory(); 其中StaticLoggerBinder 類是 logback-classic-xxx.jar 包下的 並且實現了 slfj-api-xxx.jar包的 LoggerFactoryBinder接口。 也就是說在 slf4j-api-xxx.jar包下的 getILoggerFactory 方法中調用了logback-classic-xxx.jar 包的StaticLoggerBinder類中的方法並且 該類實現了slf4j-api-xxx.jar 中的 LoggerFactoryBinder接口。
public ILoggerFactory getLoggerFactory() { if (!initialized) { return defaultLoggerContext; } if (contextSelectorBinder.getContextSelector() == null) { throw new IllegalStateException("contextSelector cannot be null. See also " + NULL_CS_URL); } return contextSelectorBinder.getContextSelector().getLoggerContext(); }
而在getLoggerContext()方法中 StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext) 這段代碼傳入的參數是LoggerContext 是logback-class-xxx.jar 包中的。 並且StatusPrinter類是 logback-core-xxx.jar包中的。
這樣就形成了繼承關系為: logback-core-xxx.jar --> logback-classic-xxx.jar --> slf4j-api-xxx.jar --> 自己的代碼。
可能有疑問是slf4j怎樣知道與誰整合拿誰的LoggerFactory , 其實是通過不同的jar包來實現的。
slf4j與log4j整合導入的jar包為
-
- slf4j-api.jar
- slf4j-log4j12.jar
- log4j.jar
slf4j與log4j2整合導入的jar包為:
-
- slf4j-api.jar
- log4j-slf4j-impl.jar
- log4j-api.jar
- log4j-core.jar
slf4j與logback整合導入的jar包為:
-
- slf4j-api.jar
- logback-core.jar
- logback-classic.jar
所以這樣當更換日志框架的時候 slf4j接口是不用動的,只需要換下對應的實現框架的包就可以了。並且代碼不用更改。
本文純屬原創, 轉載請注明出處!