問題java
使用slf4j和logback記錄日誌,有這樣一個需求,若是指定了一個特定logback.xml,就用指定的配置,若是沒有,則系統提供一個默認的配置。app
解決ide
classpath下放一個配置文件logback.xml,使用環境變量logback.configurationFile指定另外一個配置。logback會首先使用環境變量指定的文件,若是沒有指定或文件不存在,logback會使用classpath下的文件。this
原理 - logback配置文件查找過程url
1. 使用以下代碼獲取日誌器spa
import org.slf4j.Logger; import org.slf4j.LoggerFactory; Logger logger = LoggerFactory.getLogger(LogTest.class);
2. slf4j首先會判斷有沒有初始化過
日誌
org.slf4j.LoggerFactory
public static Logger getLogger(Class<?> clazz) { Logger logger = getLogger(clazz.getName()); ... return logger; } public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); } public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { synchronized (LoggerFactory.class) { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITIALIZATION; performInitialization(); } } } ... }
3. 若是沒有初始化過,則執行初始化,初始化的過程是加載org.slf4j.impl.StaticLoggerBinder類orm
private final static void performInitialization() { bind(); ... } private final static void bind() { ... staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); ... } private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"; static Set<URL> findPossibleStaticLoggerBinderPathSet() { // use Set instead of list in order to deal with bug #138 // LinkedHashSet appropriate here because it preserves insertion order during iteration Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>(); try { ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader(); Enumeration<URL> paths; if (loggerFactoryClassLoader == null) { paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH); } else { 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; }
4. 加載StaticLoggerBinder類的初始化過程xml
org.slf4j.impl.StaticLoggerBinder
static { SINGLETON.init(); } void init() { new ContextInitializer(defaultLoggerContext).autoConfig(); }
ch.qos.logback.classic.util.ContextInitializer
final public static String GROOVY_AUTOCONFIG_FILE = "logback.groovy"; final public static String AUTOCONFIG_FILE = "logback.xml"; final public static String TEST_AUTOCONFIG_FILE = "logback-test.xml"; final public static String CONFIG_FILE_PROPERTY = "logback.configurationFile"; public void autoConfig() throws JoranException { URL url = findURLOfDefaultConfigurationFile(true); if (url != null) { configureByResource(url); } else { Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class); if (c != null) { try { c.setContext(loggerContext); c.configure(loggerContext); } catch (Exception e) { throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass() .getCanonicalName() : "null"), e); } } else { BasicConfigurator basicConfigurator = new BasicConfigurator(); basicConfigurator.setContext(loggerContext); basicConfigurator.configure(loggerContext); } } } public URL findURLOfDefaultConfigurationFile(boolean updateStatus) { ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this); URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus); if (url != null) { return url; } url = getResource(GROOVY_AUTOCONFIG_FILE, myClassLoader, updateStatus); if (url != null) { return url; } url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus); if (url != null) { return url; } return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus); } private URL findConfigFileURLFromSystemProperties(ClassLoader classLoader, boolean updateStatus) { String logbackConfigFile = OptionHelper.getSystemProperty(CONFIG_FILE_PROPERTY); ... }
可見,logback加載的過程是接口
(1)使用logback.configurationFile環境變量的設置
(2)使用classpath中的logback.groovy
(3)使用classpath中的logback-test.xml
(4)使用classpath中的logback.xml
(5)查找com.qos.logback.classic.spi.Configurator接口實現類,調用實現類的configure方法設置
(6)使用BasicConfigurator類的configure方法設置