springboot項(xiàng)目突然啟動(dòng)緩慢的解決
springboot項(xiàng)目突然啟動(dòng)緩慢
springboot項(xiàng)目在debug模式下本來(lái)運(yùn)行的挺快,后來(lái)某一天突然啟動(dòng)一半就卡在那一點(diǎn)一點(diǎn)龜速前進(jìn),還以為是我電腦問(wèn)題,或者我寫的代碼問(wèn)題,后來(lái)在網(wǎng)上搜了一下,結(jié)合自身項(xiàng)目情況,原來(lái)是斷點(diǎn)問(wèn)題,
有個(gè)斷點(diǎn)無(wú)論如何都去不掉??赡苁侵斑z留的,后代碼刪除了,
也可能是因?yàn)檫@個(gè)地方的代碼屬于加載運(yùn)行的什么節(jié)點(diǎn),總之去不掉
后來(lái)根據(jù)網(wǎng)上的方法,在debug模式窗口下,選擇Run菜單,點(diǎn)擊Remove All Breakpoints的選項(xiàng)(好像也可以選擇Skip All Breakpoing。)
然后所有斷點(diǎn)都去掉了,重新啟動(dòng),流暢!!!
springboot啟動(dòng)太慢優(yōu)化
接下來(lái)我們一起探討下每個(gè)問(wèn)題。
1.組件自動(dòng)掃描帶來(lái)的問(wèn)題(@SpringBootApplication)
我們?cè)诘谝黄┛途徒榻B了,我們默認(rèn)情況下,我們會(huì)使用@SpringBootApplication注解來(lái)自動(dòng)獲取應(yīng)用的配置信息,但這樣也會(huì)帶來(lái)一些副作用。使用這個(gè)注解后,會(huì)觸發(fā)自動(dòng)配置(auto-configuration)和組件掃描(component scanning),這跟使用@Configuration、@EnableAutoConfiguration和@ComponentScan三個(gè)注解的作用是一樣的。這樣做給開發(fā)帶來(lái)方便的同時(shí),會(huì)有以下的一些影響:
(a)會(huì)導(dǎo)致項(xiàng)目啟動(dòng)時(shí)間變長(zhǎng)(原因:加載了我們不需要使用的組件,浪費(fèi)了cpu資源和內(nèi)存資源)。當(dāng)啟動(dòng)一個(gè)大的應(yīng)用程序,或?qū)⒆龃罅康募蓽y(cè)試啟動(dòng)應(yīng)用程序時(shí),影響會(huì)特別明顯。
(b)會(huì)加載一些不需要的多余的實(shí)例(beans)。
(c)會(huì)增加CPU消耗和內(nèi)存的占用。
2.如何避免組件自動(dòng)掃描帶來(lái)的問(wèn)題(不使用@ SpringBootApplication)
本著有問(wèn)題就要解決的心態(tài),針對(duì)以上的問(wèn)題,我們要怎么解決呢?很明顯,既然@SpringBootApplication加載了一些不必要的配置,那么我們想是否可以就加載我們自己指定的配置呢?我們的思路不使用@SpringBootApplication,并且不使用@ComponentScan注解(此注解會(huì)自動(dòng)掃描我們注解了@Controller,@Service的注解的類,加載到Spring IOC容器中),然后我們使用@Configuration和@EnableAutoConfiguration進(jìn)行配置啟動(dòng)類,代碼如下:
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 --守護(hù)天使
* @version v.0.1
* @date 2017年3月11日
*/
//移除 @SpringBootApplication and @ComponentScan, 用 @EnableAutoConfiguration 來(lái)替代
@Configuration
@EnableAutoConfiguration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
3.引發(fā)的問(wèn)題——無(wú)法掃描組件
我們正要為我們的代碼改良慶幸的時(shí)候,我們發(fā)現(xiàn)問(wèn)題來(lái)了。啟動(dòng)之后,訪問(wèn)我們編寫的訪問(wèn)頁(yè)面/index,
出現(xiàn)錯(cuò)誤:There was an unexpected error (type=Not Found, status=404).
這是由于什么引起的呢?還記得我們剛剛介紹的@ComponentScan注解嘛,啟用這個(gè)注解Spring才能夠進(jìn)行自動(dòng)組件的掃描,否則無(wú)法掃描到我們編寫的組件類。那么問(wèn)題來(lái)了,怎么辦呢?問(wèn)題的解決就是:顯式進(jìn)行配置。
注入代碼如下(假設(shè)我們寫的類是HelloController,在這里博主直接寫在App.java啟動(dòng)類進(jìn)行注入):
@Bean
public HelloController helloController(){
return new HelloController();
}
在以上的代碼中用 @Bean 注解明確顯式配置,以便被 Spring 掃描到。
在重新啟動(dòng)之后,我們就可以正常訪問(wèn)/index頁(yè)面了。
到這里肯定就會(huì)有人會(huì)說(shuō):那這樣的話,不是會(huì)增加我們的編碼量。我只能說(shuō):你既要加載快,又要不編碼,博主實(shí)在不知道怎么辦了。凡事有利有弊,自己權(quán)衡利弊。
4.千古紅樓只一夢(mèng),竹籃打水一場(chǎng)空
有人不相信,這個(gè)真的能啟動(dòng)更快嗎,于是乎就編碼進(jìn)行測(cè)試。哈哈,露餡了,還是一樣啟動(dòng)的跟蝸牛一樣慢。那為什么是這樣呢?為什么我們研究了半天,最終卻是:千古紅樓只一夢(mèng),竹籃打水一場(chǎng)空。
聰明的讀者,會(huì)注意到我們提到:@SpringBootApplication注解的作用跟@EnableAutoConfiguration注解的作用是相當(dāng)?shù)?,那就意味著它也能帶?lái)上述的問(wèn)題。要避免這些問(wèn)題,我們就要知道我們的組件列表是哪些?
5.debug debug,bug bug更健康
我們?cè)谏厦嬲f(shuō)了,我們的問(wèn)題就是如何知道我們的組件列表是哪些?這時(shí)候debug就隆重登場(chǎng)了,鼓掌歡迎debug先生上場(chǎng)。
請(qǐng)問(wèn)debug先生:在此時(shí)此刻您有什么獲獎(jiǎng)感言?
debug先生:經(jīng)歷了慢慢人生,我終于發(fā)現(xiàn)我的價(jià)值了。在這里我要感謝CCTV、感謝MTV、感謝可口可樂,感謝非??蓸贰⒏兄x加多寶、感謝王老吉、感謝主辦方SpringBoot,讓我有機(jī)會(huì)在這個(gè)舞臺(tái)跟大家見面。謝謝你們,我一定不會(huì)讓大家失望的。
好了,廢話不多說(shuō)了,我們先看看如何使用debug呢?
第一種情況:使用spring-boot:run啟動(dòng)方式
這種情況的話,完整的運(yùn)行代碼是:
spring-boot:run -Ddebug
第二種情況:使用Run As —— Java Application啟動(dòng)方式
這種情況的話,配置VM參數(shù)即可,具體操作如下:
【右鍵】——【Run As】——【Run Configurations…】——【選擇Arguments】——【VM arguments】中加入:【-Ddebug】。
這時(shí)候在啟動(dòng)的時(shí)候,我們就能看到控制臺(tái)打印出了一些我們平時(shí)沒看到過(guò)的日志信息。
=========================
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
在打印信息里,我們有必要先了解下這里的一些知識(shí):
(a) Positive match:累出匹配到對(duì)應(yīng)類的配置項(xiàng)。
(b) Negative match:不包括某個(gè)配置項(xiàng)的原因。
現(xiàn)在以DataSourceAutoConfiguration舉例說(shuō)明:
(a)@ConditionalOnClass表示對(duì)應(yīng)的類在classpath目錄下存在時(shí),才會(huì)去解析對(duì)應(yīng)的配置文件,對(duì)于DataSourceAutoConfiguration來(lái)說(shuō)就是指:只有javax.sql.DataSource和org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType類都存在時(shí),就會(huì)配置對(duì)應(yīng)的數(shù)據(jù)庫(kù)資源。
(b)@ConditionalOnMissingClass表示對(duì)應(yīng)的類在classpath目錄下找不到。
(c)OnClassCondition用于表示匹配的類型(postive or negative)。
OnClassCondition是最普遍的瀏覽探測(cè)條件,除此之外,Spring Boot也使用別的探測(cè)條件,如:OnBeanCondition用于檢測(cè)指定bean實(shí)例存在與否、OnPropertyCondition用于檢查指定屬性是否存在等等。
符合negative match代表一些配置類(xxxConfiguration之類的),它們雖然存在于classpath目錄,但是修飾它們的注解中依賴的其他類不存在。
7.再次優(yōu)化配置信息
根據(jù)上面的理論知識(shí),我們只需要在啟動(dòng)的時(shí)候,顯式地引入這些組件,拷貝Positive matches中列出的信息:
DispatcherServletAutoConfiguration EmbeddedServletContainerAutoConfiguration ErrorMvcAutoConfiguration HttpEncodingAutoConfiguration HttpMessageConvertersAutoConfiguration JacksonAutoConfiguration JmxAutoConfiguration MultipartAutoConfiguration ServerPropertiesAutoConfiguration PropertyPlaceholderAutoConfiguration ThymeleafAutoConfiguration WebMvcAutoConfiguration WebSocketAutoConfiguration
然后來(lái)更新項(xiàng)目配置,顯式地引入這些組件,引入之后,再運(yùn)行一下應(yīng)用確保沒有錯(cuò)誤發(fā)生:
@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 {
在上面的代碼中,我們可以刪掉我們不需要的組件信息,來(lái)挺高應(yīng)用的性能,比如在項(xiàng)目中沒有使用Jmx和WebSocket功能的話,那么我們就可以刪除JmxAutoConfiguration.class和WebSocketAutoConfiguration.class。
刪除掉之后,再次運(yùn)行項(xiàng)目,確保一切正常。
8.小結(jié)一下
在本篇文章中我們介紹了如何加速spring boot快速啟動(dòng),主要的思路就是廢棄@SpringBootApplication顯式的引入我們所需要的組件。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Cloud Gateway重試機(jī)制原理解析
這篇文章主要介紹了Spring Cloud Gateway重試機(jī)制原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
Java編程數(shù)組中最大子矩陣簡(jiǎn)便解法實(shí)現(xiàn)代碼
這篇文章主要介紹了Java編程數(shù)組中最大子矩陣簡(jiǎn)便解法實(shí)現(xiàn)代碼,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
@RequestBody 部分屬性沒有轉(zhuǎn)化成功的處理
這篇文章主要介紹了@RequestBody 部分屬性沒有轉(zhuǎn)化成功的處理方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
構(gòu)建多模塊的Spring Boot項(xiàng)目步驟全紀(jì)錄
這篇文章主要給大家介紹了關(guān)于如何構(gòu)建多模塊的Spring Boot項(xiàng)目的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用SpringBoot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
Java ThreadLocal詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲(chǔ),本文會(huì)詳細(xì)的介紹一下,有興趣的可以了解一下2017-06-06
Java Collections.EMPTY_LIST與Collections.emptyList()的區(qū)別
這篇文章主要介紹了Java Collections.EMPTY_LIST與Collections.emptyList()的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
通過(guò)String.intern()方法淺談堆中常量池
這篇文章主要介紹了通過(guò)String.intern()方法淺談堆中常量池,在JDK7之前,字符串常量是存在永久帶Perm 區(qū)的,JDK7開始在將常量池遷移到堆中,這個(gè)變化也導(dǎo)致了String的新特性,下面我們慢慢進(jìn)行介紹。,需要的朋友可以參考下2019-06-06
使用sharding-jdbc實(shí)現(xiàn)水平分庫(kù)+水平分表的示例代碼
本文主要介紹了使用sharding-jdbc實(shí)現(xiàn)水平分庫(kù)+水平分表,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12

