springboot項目突然啟動緩慢的解決
springboot項目突然啟動緩慢
springboot項目在debug模式下本來運行的挺快,後來某一天突然啟動一半就卡在那一點一點龜速前進,還以為是我電腦問題,或者我寫的代碼問題,後來在網上搜瞭一下,結合自身項目情況,原來是斷點問題,
有個斷點無論如何都去不掉。可能是之前遺留的,後代碼刪除瞭,
也可能是因為這個地方的代碼屬於加載運行的什麼節點,總之去不掉
後來根據網上的方法,在debug模式窗口下,選擇Run菜單,點擊Remove All Breakpoints的選項(好像也可以選擇Skip All Breakpoing。)
然後所有斷點都去掉瞭,重新啟動,流暢!!!
springboot啟動太慢優化
接下來我們一起探討下每個問題。
1.組件自動掃描帶來的問題(@SpringBootApplication)
我們在第一篇博客就介紹瞭,我們默認情況下,我們會使用@SpringBootApplication註解來自動獲取應用的配置信息,但這樣也會帶來一些副作用。使用這個註解後,會觸發自動配置(auto-configuration)和組件掃描(component scanning),這跟使用@Configuration、@EnableAutoConfiguration和@ComponentScan三個註解的作用是一樣的。這樣做給開發帶來方便的同時,會有以下的一些影響:
(a)會導致項目啟動時間變長(原因:加載瞭我們不需要使用的組件,浪費瞭cpu資源和內存資源)。當啟動一個大的應用程序,或將做大量的集成測試啟動應用程序時,影響會特別明顯。
(b)會加載一些不需要的多餘的實例(beans)。
(c)會增加CPU消耗和內存的占用。
2.如何避免組件自動掃描帶來的問題(不使用@ SpringBootApplication)
本著有問題就要解決的心態,針對以上的問題,我們要怎麼解決呢?很明顯,既然@SpringBootApplication加載瞭一些不必要的配置,那麼我們想是否可以就加載我們自己指定的配置呢?我們的思路不使用@SpringBootApplication,並且不使用@ComponentScan註解(此註解會自動掃描我們註解瞭@Controller,@Service的註解的類,加載到Spring IOC容器中),然後我們使用@Configuration和@EnableAutoConfiguration進行配置啟動類,代碼如下:
package com.kfit.spring_boot_performance; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.kfit.spring_boot_performance.controller.HelloController; /** * @author Angel --守護天使 * @version v.0.1 * @date 2017年3月11日 */ //移除 @SpringBootApplication and @ComponentScan, 用 @EnableAutoConfiguration 來替代 @Configuration @EnableAutoConfiguration public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
3.引發的問題——無法掃描組件
我們正要為我們的代碼改良慶幸的時候,我們發現問題來瞭。啟動之後,訪問我們編寫的訪問頁面/index,
出現錯誤:There was an unexpected error (type=Not Found, status=404).
這是由於什麼引起的呢?還記得我們剛剛介紹的@ComponentScan註解嘛,啟用這個註解Spring才能夠進行自動組件的掃描,否則無法掃描到我們編寫的組件類。那麼問題來瞭,怎麼辦呢?問題的解決就是:顯式進行配置。
註入代碼如下(假設我們寫的類是HelloController,在這裡博主直接寫在App.java啟動類進行註入):
@Bean public HelloController helloController(){ return new HelloController(); }
在以上的代碼中用 @Bean 註解明確顯式配置,以便被 Spring 掃描到。
在重新啟動之後,我們就可以正常訪問/index頁面瞭。
到這裡肯定就會有人會說:那這樣的話,不是會增加我們的編碼量。我隻能說:你既要加載快,又要不編碼,博主實在不知道怎麼辦瞭。凡事有利有弊,自己權衡利弊。
4.千古紅樓隻一夢,竹籃打水一場空
有人不相信,這個真的能啟動更快嗎,於是乎就編碼進行測試。哈哈,露餡瞭,還是一樣啟動的跟蝸牛一樣慢。那為什麼是這樣呢?為什麼我們研究瞭半天,最終卻是:千古紅樓隻一夢,竹籃打水一場空。
聰明的讀者,會註意到我們提到:@SpringBootApplication註解的作用跟@EnableAutoConfiguration註解的作用是相當的,那就意味著它也能帶來上述的問題。要避免這些問題,我們就要知道我們的組件列表是哪些?
5.debug debug,bug bug更健康
我們在上面說瞭,我們的問題就是如何知道我們的組件列表是哪些?這時候debug就隆重登場瞭,鼓掌歡迎debug先生上場。
請問debug先生:在此時此刻您有什麼獲獎感言?
debug先生:經歷瞭慢慢人生,我終於發現我的價值瞭。在這裡我要感謝CCTV、感謝MTV、感謝可口可樂,感謝非常可樂、感謝加多寶、感謝王老吉、感謝主辦方SpringBoot,讓我有機會在這個舞臺跟大傢見面。謝謝你們,我一定不會讓大傢失望的。
好瞭,廢話不多說瞭,我們先看看如何使用debug呢?
第一種情況:使用spring-boot:run啟動方式
這種情況的話,完整的運行代碼是:
spring-boot:run -Ddebug
第二種情況:使用Run As —— Java Application啟動方式
這種情況的話,配置VM參數即可,具體操作如下:
【右鍵】——【Run As】——【Run Configurations…】——【選擇Arguments】——【VM arguments】中加入:【-Ddebug】。
這時候在啟動的時候,我們就能看到控制臺打印出瞭一些我們平時沒看到過的日志信息。
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:
—————–DispatcherServletAutoConfiguration matched
– @ConditionalOnClass found required class ‘org.springframework.web.servlet.DispatcherServlet’ (OnClassCondition)
– @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
//此處省略剩下的打印信息…
6.分析Positive matches和Negative matches
在打印信息裡,我們有必要先瞭解下這裡的一些知識:
(a) Positive match:累出匹配到對應類的配置項。
(b) Negative match:不包括某個配置項的原因。
現在以DataSourceAutoConfiguration舉例說明:
(a)@ConditionalOnClass表示對應的類在classpath目錄下存在時,才會去解析對應的配置文件,對於DataSourceAutoConfiguration來說就是指:隻有javax.sql.DataSource和org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType類都存在時,就會配置對應的數據庫資源。
(b)@ConditionalOnMissingClass表示對應的類在classpath目錄下找不到。
(c)OnClassCondition用於表示匹配的類型(postive or negative)。
OnClassCondition是最普遍的瀏覽探測條件,除此之外,Spring Boot也使用別的探測條件,如:OnBeanCondition用於檢測指定bean實例存在與否、OnPropertyCondition用於檢查指定屬性是否存在等等。
符合negative match代表一些配置類(xxxConfiguration之類的),它們雖然存在於classpath目錄,但是修飾它們的註解中依賴的其他類不存在。
7.再次優化配置信息
根據上面的理論知識,我們隻需要在啟動的時候,顯式地引入這些組件,拷貝Positive matches中列出的信息:
DispatcherServletAutoConfiguration EmbeddedServletContainerAutoConfiguration ErrorMvcAutoConfiguration HttpEncodingAutoConfiguration HttpMessageConvertersAutoConfiguration JacksonAutoConfiguration JmxAutoConfiguration MultipartAutoConfiguration ServerPropertiesAutoConfiguration PropertyPlaceholderAutoConfiguration ThymeleafAutoConfiguration WebMvcAutoConfiguration WebSocketAutoConfiguration
然後來更新項目配置,顯式地引入這些組件,引入之後,再運行一下應用確保沒有錯誤發生:
@Configuration @Import({ DispatcherServletAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class, ErrorMvcAutoConfiguration.class, HttpEncodingAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class, JmxAutoConfiguration.class, MultipartAutoConfiguration.class, ServerPropertiesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, ThymeleafAutoConfiguration.class, WebMvcAutoConfiguration.class, WebSocketAutoConfiguration.class, }) public class App {
在上面的代碼中,我們可以刪掉我們不需要的組件信息,來挺高應用的性能,比如在項目中沒有使用Jmx和WebSocket功能的話,那麼我們就可以刪除JmxAutoConfiguration.class和WebSocketAutoConfiguration.class。
刪除掉之後,再次運行項目,確保一切正常。
8.小結一下
在本篇文章中我們介紹瞭如何加速spring boot快速啟動,主要的思路就是廢棄@SpringBootApplication顯式的引入我們所需要的組件。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- SpringBoot自動配置特點與原理詳細分析
- Springboot常用註解及配置文件加載順序詳解
- SpringBoot自動配置與啟動流程詳細分析
- springboot bean掃描路徑的實現
- SpringBoot零基礎入門之基本操作與概念