SpringBoot之logback-spring.xml不生效
一、前言
做新應用就是這樣,會遇到各種問題,昨天剛解決了載入某一個類時候丟擲了class is not visible from class loader
的問題,今天就有遇到了日誌檔案找不到的問題,還是和二方庫有關的,下面就一一道來。
二、問題產生
- 正常情況下在
src/main/resources
目錄放下logback-spring.xml
的配置檔案(使用logback日誌系統),如下圖 image.png - application.properties裡面設定
spring.application.name=spring-boot-demo-application
- 引入了一個二方包,二方包裡面有
logback.xml
按照上面配置,執行後正常情況下我們希望在 user.home/spring-boot-demo-application/logs
目錄應該有applicaiton.log
日誌檔案,然而並沒有,連spring-boot-demo-application
這個資料夾都沒有生成。
三、問題分析
那麼我們就去看看日誌系統是如何查詢並解析日誌配置檔案的,SpringBoot中是使用LoggingApplicationListener這個類來進行日誌系統的初始化的。LoggingApplicationListener實現了ApplicationListener介面,那麼我們通過時序圖看LoggingApplicationListener的onApplicationEvent方法做了啥:
- 程式碼(8)查詢標準日誌配置檔案,什麼是標準那,那麼就看程式碼(9)的程式碼:
protected String[] getStandardConfigLocations() {
return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy",
"logback.xml" };
}
像 "logback-test.groovy", "logback-test.xml", "logback.groovy","logback.xml"
那麼具體怎麼查詢那,要看程式碼(10):
private String findConfig(String[] locations) {
for (String location : locations) {
ClassPathResource resource = new ClassPathResource(location,
this.classLoader);
if (resource.exists()) {
return "classpath:" + location;
}
}
return null;
}
可知使用ClassPathResource類去查詢,下面看ClassPathResource的exists方法:
public boolean exists() {
return (resolveURL() != null);
}
protected URL resolveURL() {
if (this.clazz != null) {
return this.clazz.getResource(this.path);
}
else if (this.classLoader != null) {
return this.classLoader.getResource(this.path);
}
else {
return ClassLoader.getSystemResource(this.path);
}
}
可知是使用 this.classLoader.getResource(this.path);
去查詢這裡classLoader為AppClassloader。
- 如果程式碼(8)沒有查詢到配置,則執行點(12),程式碼12邏輯和程式碼(8)類似只是查詢檔名字不一樣,下面看下:
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;
}
可知是在getStandardConfigLocations的檔名上拼接spring,拼接後的檔名為:
“` “logback-test-spring.groovy”, “logback-test-spring.xml”, “logback-spring.groovy”,”logback-spring.xml” “
綜上所述SpringBoot首先去查詢標準的日誌配置檔案,如果找不到在去找拼接Spring的配置的檔案。
那麼上面我們說了應用中是引入了一個含有logback.xml的jar包,而這個jar包也是使用appclassloader載入的,所以在執行步驟(8)的時候找到了jar包裡面的logback.xml,所以就不會再去執行步驟(12)來找我們自定義的logback-spring.xml了。
四、問題解決
- 方案一,修改我們的配置檔案為logback.xml,這樣在步驟(8)的時候會首先查詢logback.xml,應該是可以找到的。
- 方案二、避免二方包裡面含有logback.xml,這種情況下,無論我們自己的配置是logback-spring.xml還是logback.xml都不會有問題。
五、總結
日常開發中二方包裡面不要帶有日誌配置檔案,二方庫中使用日誌一般都是使用程式碼建立的方式。
歡迎關注微信公眾號 ‘技術原始積累’