開心一刻
一大早,她就發訊息質問我
她:你給我老實交代,昨晚去哪鬼混了?
我:沒有,就哥幾個喝了點酒
她:那我給你打了那麼多影片,為什麼不接?
我:不太方便呀
她:我不信,和你哥們兒喝酒有啥不方便接影片的?
她:你肯定有別的女人了!
我:你老公就坐在我旁邊,我敢接?
前情回顧
SpringBoot2.7還是任性的,就是不支援Logback1.3,你能奈他何 講了很多,總結下來就兩點
-
SpringBoot 2.7.x 預設依賴 Logback 1.2.x,不支援 Logback 1.3.x
如果強行將 Logback 升級到 1.3.x,啟動會報異常
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:304) at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:118) at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationStartingEvent(LoggingApplicationListener.java:238) at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:220) at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:145) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:133) at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:79) at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:56) at java.util.ArrayList.forEach(ArrayList.java:1249) at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120) at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:56) at org.springframework.boot.SpringApplication.run(SpringApplication.java:299) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) at com.qsl.Application.main(Application.java:15) Caused by: java.lang.ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 17 more
原因也分析過了
spring-boot-2.7.18 依賴 org.slf4j.impl.StaticLoggerBinder,而 logback 1.3.x 沒有該類
-
SpringBoot 2.7.x 支援 Logback 1.3.x 也不是沒辦法,但有一些限制,同時也存在一些未知的風險
關於未知的風險,相信大家都能理解,為什麼了,這就好比從
JDK8
升級到JDK 11
,你們為什麼不敢升,一個道理,因為大版本的升級,變動點往往比較多,甚至會移除掉低版本的一些內容,編譯期報錯還算直觀的(我們可以根據報錯調整程式碼),如果是執行期報錯那就頭疼了,上了生產就算事故了,這鍋你敢背嗎?
所以大版本的升級,意味著我們不但要修復編譯期的錯,還要進行全方位的測試,儘可能的覆蓋所有場景,以排除執行期可能存在的任何異常。業務簡單還好,如果業務非常龐大,這個全量測試是要花大量時間的,不僅開發會口吐芬芳,測試也會mmp
Upgrade to SLF4J 2.0 and Logback 1.4 進行了一些討論,wilkinsona
(Spring Boot 目前 Contributor 榜一)就提到了一些風險點裡面討論了很多,
Logback
的 Contributor 榜一大哥ceki
也在裡面進行了很多說明與答疑,感興趣的可以詳細看看
總之就是:透過調整配置,SpringBoot 2.7.x 可以支援 Logback 1.3.x,但風險需要我們自己承擔
換個角度想想,我們應該是能理解 Spring Boot
官方的
- 對
Logback
不是那麼熟,只能透過Logback
官方說明知道變動點(能保證事無鉅細列全了?),若變動點太多,不可能每個點都去核實 Spring Boot
那麼龐大,整合了那麼多功能,怕是榜一大哥也不能熟記所有細節(我們敢保證對我們負責的專案的所有細節都瞭如指掌嗎),所以也沒法評估升級到Logback 1.3.x
會有哪些點受影響
所以求穩,Spring Boot 2.x.x
不打算整合 Logback 1.3.x
但是,如果我們也任性一回,非要強扭這個瓜,Spring Boot
是不是也不能奈我們何?
霸王硬上弓
參考這個,我們來配置下
-
關閉
Spring Boot
的LoggingSystem
@SpringBootApplication public class Application { public static void main(String[] args) { System.setProperty("org.springframework.boot.logging.LoggingSystem", "none"); SpringApplication.run(Application.class, args); } }
-
配置檔案用
logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="LOG_FILE" value="/logs/spring-boot-2_7_18.log"/> <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}|%level|%t|%line|%-40.40logger{39}:%msg%n"/> <!-- 按照每天生成日誌檔案--> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.zip</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> </appender> <!-- 控制檯輸出 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}}</pattern> </encoder> </appender> <root level="${loglevel:-INFO}"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </root> </configuration>
啟動確實正常了,我們加點簡單的業務日誌,發現日誌也輸出正常
2024-07-26 16:46:48.609|INFO|http-nio-8080-exec-1|525|o.s.web.servlet.DispatcherServlet :Initializing Servlet 'dispatcherServlet'
2024-07-26 16:46:48.610|INFO|http-nio-8080-exec-1|547|o.s.web.servlet.DispatcherServlet :Completed initialization in 0 ms
2024-07-26 16:46:48.632|INFO|http-nio-8080-exec-1|23|com.qsl.web.TestWeb :hello介面入參:青石路
2024-07-26 16:46:50.033|INFO|http-nio-8080-exec-3|23|com.qsl.web.TestWeb :hello介面入參:青石路
2024-07-26 16:46:50.612|INFO|http-nio-8080-exec-4|23|com.qsl.web.TestWeb :hello介面入參:青石路
2024-07-26 16:46:51.150|INFO|http-nio-8080-exec-5|23|com.qsl.web.TestWeb :hello介面入參:青石路
2024-07-26 16:46:51.698|INFO|http-nio-8080-exec-6|23|com.qsl.web.TestWeb :hello介面入參:青石路
2024-07-26 16:46:52.203|INFO|http-nio-8080-exec-7|23|com.qsl.web.TestWeb :hello介面入參:青石路
日誌檔案寫入也正常
這不僅解渴,還很甜呀
但不要甜的太早,這僅僅只是一個 demo
:spring-boot-2_7_18,沒有業務程式碼,簡單的不能再簡單了,你們要是以此來判斷甜與不甜,那就大錯特錯了;應用到專案中,不但要保證能夠正常啟動,還要保證已有的所有業務能夠正常執行,至於計劃中的業務,那就將來再說,誰知道明天和意外哪個先來,認真過好當下!
初步嘗試,是可行的,所以你們大膽的去試吧,但要做好全方位的業務測試
wilkinsona
提到了,關閉 Spring Boot
的 LoggingSystem
後,用的是 Logback
的預設配置,配置檔案必須是 logback.xml
而不能是 logback-spring.xml
;雖然榜一大哥的話很權威,但我們主打一個任性,就想來試試 logback-spring.xml
,會有什麼樣的結果,直接將 logback.xml
改名成 logback-spring.xml
,能啟動起來,但有一堆 debug
日誌,重點是
日誌沒有寫入檔案
wilkinsona
誠不欺我!
原理分析
關閉了 Spring Boot
的 LoggingSystem
後,日誌相關的全權交給 Logback
,而關於 Logback
的配置檔案載入,我是寫過一篇詳解的:從原始碼來理解slf4j的繫結,以及logback對配置檔案的載入,直接跳到總結部分,有這麼一段
編譯期間,完成slf4j的繫結以及logback配置檔案的載入。slf4j會在classpath中尋找org/slf4j/impl/StaticLoggerBinder.class(會在具體的日誌框架如log4j、logback等中存在),找到並完成繫結;同時,logback也會在classpath中尋找配置檔案,先找logback.configurationFile、沒有則找logback.groovy,若logback.groovy也沒有,則找logback-test.xml,若logback-test.xml還是沒有,則找logback.xml,若連logback.xml也沒有,那麼說明沒有配置logback的配置檔案,那麼logback則會啟用預設的配置(日誌資訊只會列印在控制檯)
雖說 Logback
是 1.1.17
,而不是 1.3.14
,但對配置檔案的載入應該是沒變的
大家注意看我的措辭:應該,這樣即使變了,你們也不能說我,因為我說的是應該
保險起見,你們應該去看下 1.3.14 的原始碼!
這也是為什麼配置檔案是 logback.xml
的時候,日誌能正常寫入檔案,而是 logback-spring.xml
時候,日誌不能寫入日誌檔案的原因,因為 Logback
不認 logback-spring.xml
,Spring Boot
才認!
至於 Spring Boot LoggingSystem
嘛,等我掌握了再來和你們聊,一定要等我喲
總結
Spring Boot 2.x.x
預設依賴 Logback 1.2.x
,不支援 Logback 1.3.x
,但是透過設定
System.setProperty("org.springframework.boot.logging.LoggingSystem", "none");
啟動時不報錯的,再結合 logback.xml
,日誌是能夠正常寫入日誌檔案的;但是保險起見,還是不推薦升級到 Logback 1.3.x
能不動就不要動,改好沒績效,改出問題要背鍋,吃力不討好,又不是不能跑
如果一定要升級,那就做好全量測試,把所有業務場景都覆蓋到