Spring Boot中logback配置文件載入過程

這裡不會列舉Spring Boot中logback配置語法,網上很多。

這裡主要過一下logback在Spring Boot應用中是如何初始化的,以及載入logback相關配置文件的順序。

先列出幾點:

  • 如果classpath下有logback-test.xml會優先生效,xxx-spring.xml優先順序最低。
  • 日誌系統初始化之前日誌輸出有DEBUG,因為此刻logback-spring還未生效,spring boot默認日誌級別是DEBUG。
  • 有些依賴的庫日誌輸出不受控制,是因為最終使用的logger不是logback,比如使用的log4j。
  • Spring Boot使用JUnit測試時使用SpringBootTest註解與否在日誌系統初始化時有區別。

下面通過瀏覽代碼看看具體的過程。

在Spring應用啟動時會先獲取到對應的日誌實例。

// org.springframework.boot.logging.LoggingApplicationListenerprivate void onApplicationStartedEvent(ApplicationStartedEvent event) { this.loggingSystem = LoggingSystem .get(event.getSpringApplication().getClassLoader()); this.loggingSystem.beforeInitialize();}

檢測和獲取日誌系統,檢測的順序定義在SYSTEMS中,最終通過反射創建LogbackLoggingSystem實例。

// org.springframework.boot.logging.LoggingSystempublic static LoggingSystem get(ClassLoader classLoader) { String loggingSystem = System.getProperty(SYSTEM_PROPERTY);// null if (StringUtils.hasLength(loggingSystem)) { if (NONE.equals(loggingSystem)) { return new NoOpLoggingSystem(); } return get(classLoader, loggingSystem); } for (Map.Entry<String, String> entry : SYSTEMS.entrySet()) { if (ClassUtils.isPresent(entry.getKey(), classLoader)) { return get(classLoader, entry.getValue()); } } throw new IllegalStateException("No suitable logging system located");}/** * A System property that can be used to indicate the {@link LoggingSystem} to use. */public static final String SYSTEM_PROPERTY = LoggingSystem.class.getName();private static final Map<String, String> SYSTEMS;static { Map<String, String> systems = new LinkedHashMap<String, String>(); systems.put("ch.qos.logback.core.Appender", "org.springframework.boot.logging.logback.LogbackLoggingSystem"); systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory", "org.springframework.boot.logging.log4j2.Log4J2LoggingSystem"); systems.put("java.util.logging.LogManager", "org.springframework.boot.logging.java.JavaLoggingSystem"); SYSTEMS = Collections.unmodifiableMap(systems);}

然後在ApplicationEnvironmentPreparedEvent之後進行logback的初始化。

private void onApplicationEnvironmentPreparedEvent( ApplicationEnvironmentPreparedEvent event) { if (this.loggingSystem == null) { this.loggingSystem = LoggingSystem .get(event.getSpringApplication().getClassLoader()); } initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());} /** * Initialize the logging system according to preferences expressed through the * {@link Environment} and the classpath. * @param environment the environment * @param classLoader the classloader */protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) { new LoggingSystemProperties(environment).apply(); LogFile logFile = LogFile.get(environment); if (logFile != null) { logFile.applyToSystemProperties(); } initializeEarlyLoggingLevel(environment); initializeSystem(environment, this.loggingSystem, logFile); initializeFinalLoggingLevels(environment, this.loggingSystem); registerShutdownHookIfNecessary(environment, this.loggingSystem);}

重點看配置文件檢測的過程。

private void initializeWithConventions( LoggingInitializationContext initializationContext, LogFile logFile) { // 獲取logback自己支持的配置文件 String config = getSelfInitializationConfig(); if (config != null && logFile == null) { // self initialization has occurred, reinitialize in case of property changes reinitialize(initializationContext); return; } // 如果沒有則檢測spring相關的logback配置 if (config == null) { config = getSpringInitializationConfig(); } if (config != null) { loadConfiguration(initializationContext, config, logFile); return; } loadDefaults(initializationContext, logFile);}

logback自身配置文件的生效順序。

// org.springframework.boot.logging.logback.LogbackLoggingSystem@Overrideprotected String[] getStandardConfigLocations() { return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" };}

通過這裡可以看到spring boot中支持的logback配置文件格式,就是在logback自配置文件(logback-test.xml, logback.xml等)基礎上文件名後面加了「-spring」,如logback-test-spring, logback-spring等。

/** * Return the spring config locations for this system. By default this method returns * a set of locations based on {@link #getStandardConfigLocations()}. * @return the spring config locations * @see #getSpringInitializationConfig() */protected String[] getSpringConfigLocations() { String[] locations = getStandardConfigLocations(); for (int i = 0; i < locations.length; i++) { String extension = StringUtils.getFilenameExtension(locations[i]); locations[i] = locations[i].substring(0, locations[i].length() - extension.length() - 1) + "-spring." + extension; } return locations;}

此外,Spring Boot使用JUnit時,如果沒有配置SpringBootTest註解,日誌系統根本不會得到初始化,會使用org.slf4j.impl.StaticLoggerBinder獲取,如果在test/resource下面存在logback-test.xml則會生效,否則就使用系統默認的配置。如果配置了置SpringBootTest註解,則SpringBoot會正常的初始化,日誌系統會正常載入。

參考

Configuration in logback

Spring Boot Logging

推薦閱讀:

您和您所在的開發團隊都是怎麼列印日誌的?又是怎麼使用日誌的?

TAG:SpringBoot | 日志 | Spring |