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.LoggingApplicationListener
private void onApplicationStartedEvent(ApplicationStartedEvent event) {
this.loggingSystem = LoggingSystem
.get(event.getSpringApplication().getClassLoader());
this.loggingSystem.beforeInitialize();
}
检测和获取日志系统,检测的顺序定义在SYSTEMS中,最终通过反射创建LogbackLoggingSystem实例。
// org.springframework.boot.logging.LoggingSystem
public 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
@Override
protected 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会正常的初始化,日志系统会正常加载。
参考
编辑于 2017-07-13 21:33