Spring Boot 2.2中的延遲初始化

banq發表於2019-03-23

最近公佈的Spring Boot 2.2的第一個里程碑,引入了延遲初始化的支援。這篇文章描述了新功能,並解釋瞭如何以及何時啟用它。

懶惰是什麼意思?
自從11年前原始碼遷移到Git之前,Spring Framework已經支援了懶惰的bean初始化。預設情況下,在重新整理應用程式上下文時,將建立上下文中的每個bean並注入其依賴項。相比之下,當bean定義被配置為懶惰地初始化時,它就不會被建立,並且在需要之前不會注入其依賴項。

啟用延遲初始化
其實任何版本的Spring Boot中都可以啟用延遲初始化,前提是如果你很高興自己動手並寫一個BeanFactoryPostProcessor。Spring Boot 2.2只是讓透過引入新的方式讓其更容易:spring.main.lazy-initialization(在SpringApplication和SpringApplicationBuilder也有兩個等同的方法),當其設定true為時,應用程式中的bean定義將配置為使用延遲初始化。

spring.main.lazy-initialization=true



延遲初始化的好處
延遲初始化可以顯著減少啟動時間,因為載入的類更少,並且在應用程式啟動期間建立的bean更少。例如,使用Actuator和Spring Security的小型Web應用程式啟動時間通常在2500ms內啟動,啟用延遲初始化後會在2000ms類啟動。根據bean的依賴關係圖的結構,確切的時間因應用程式而異。

DevTools怎麼樣?
Spring Boot的DevTools已經顯著提升了開發人員的工作效率。DevTools不是每次都重新啟動JVM和應用程式,而是在同一個JVM中啟用應用程式的熱重啟。熱重啟的一個顯著優點是它使JIT更有機會最佳化啟動應用程式所涉及的程式碼。重啟幾次後,啟動原始2500ms減少了近80%,接近500ms。使用延遲初始化,我們可以做得更好。設定spring.main.lazy-initialization後,直接在IDE中看到我們的應用程式會在400ms內重啟。

懶惰初始化的缺點
正如我們在上面所看到的,啟用延遲初始化可以極大地減少啟動時間,但是您可能想要一直預設啟用它,或者想知道為什麼我們沒有決定預設啟用它。其實延遲初始化有一些缺點。
由於不再載入類,並且在需要之前不再建立bean,因此延遲初始化可能會掩蓋以前在啟動時已識別的問題。此類問題可能包括no class def found errors、記憶體不足錯誤以及由於配置錯誤導致的故障。
在Web應用程式中,延遲初始化可能導致觸發Bean初始化的HTTP請求的增加延遲,這通常只是第一個請求會這樣,但它可能會對負載平衡和自動擴充套件會產生負面影響。

這件事情開始了嗎?
如果您不確定延遲初始化對您的應用程式有什麼影響,或者您想驗證另一個框架的行為是否滿足您的需求並匹配其宣告,那麼使用偵錯程式可能會提供資訊。透過在其中一個bean的建構函式中放置一個斷點,您可以看到它何時被初始化。例如,在啟用了延遲初始化的Spring Boot Web應用程式中,您將看到@Controller的Bean只有這樣情況才會被建立:第一次請求傳送到Spring MVC DispatcherServlet或Spring WebFlux 的DispatcherHandler。

何時啟用延遲初始化
正如我們在上面所看到的,延遲初始化可以顯著改善啟動時間,但也有一些明顯的缺點,重要的是要小心啟用它。
懶惰初始化的一個領域是非常有益的,在開發過程中幾乎沒有任何缺點。當您在應用程式上進行迭代時,延遲初始化和DevTools熱重啟所提供的啟動時間縮短可以顯著提高您的工作效率。
另一個可以從延遲初始化中受益的領域是應用程式的整合測試。您可能已經在使用Spring Boot的測試片,透過限制在某些型別的測試中初始化的bean數來減少測試執行時間。延遲初始化提供了另一種實現類似最終結果的機制。如果您無法構建應用程式以使其適合測試切片,或者如果沒有可用於特定型別測試的切片,則啟用延遲初始化會將初始化的bean限制為那些測試所需要的。這將減少測試執行時間,尤其是在開發期間單獨執行測試時。

最後,您可能需要考慮在生產中啟用延遲初始化。如果你這樣做,應該小心。對於Web應用程式,容器編排可能會受益於能夠更快響應的/health端點,但您還需要了解在嚮應用程式自己的某個端點發出第一個請求時可能會增加延遲。您還應該注意在禁用延遲初始化的情況下調整應用程式的JVM大小,以避免在使用所有元件後出現任何不必要的記憶體不足錯誤。

相關文章