1. 程式人生 > >SpringBoot之logback-spring.xml不生效

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方法做了啥:

image.png
  • 程式碼(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都不會有問題。

五、總結

日常開發中二方包裡面不要帶有日誌配置檔案,二方庫中使用日誌一般都是使用程式碼建立的方式。
歡迎關注微信公眾號 ‘技術原始積累’

image.png


加多

加多

高階 Java 攻城獅 at 阿里巴巴加多,目前就職於阿里巴巴,熱衷併發程式設計、ClassLoader,Spring等開源框架,分散式RPC框架dubbo,springcloud等;愛好音樂,運動。微信公眾號:技術原始積累。知識星球賬號:技術原始積累