中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么解決spring-boot項目啟動遲緩異常排查的問題

發布時間:2022-02-28 09:24:41 來源:億速云 閱讀:229 作者:小新 欄目:開發技術

這篇文章將為大家詳細講解有關怎么解決spring-boot項目啟動遲緩異常排查的問題,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

問題背景

一個spring boot開發的項目,spring boot版本是1.5.7,攜帶的spring版本是4.1.3。開發反饋,突然在本地啟動不起來了,表象特征就是在本地IDEA上運行時,進程卡住也不退出,應用啟動時加載相關組件的日志也不輸出。癥狀如下圖:

怎么解決spring-boot項目啟動遲緩異常排查的問題

問題分析

因為沒有有用的日志信息,所以不能從日志這個層面上排查問題。但是像這種沒有輸出日志的話,一般情況下,肯定是程序內部啟動流程卡在什么地方了,只能通過打印下當前線程堆棧信息了解下。一般情況下,在服務器環境,我們會使用java工具包中的jstack 工具來查看:如jstack pid(應用java進程)。

但是,在IDEA本地開發的話,IDEA內置了一個工具,可以直接查看當前應用的線程上線文信息,如:

怎么解決spring-boot項目啟動遲緩異常排查的問題

注意下面那個箭頭指向的像照相機一樣的圖標,故圖思意,就是打印當前線程快照的的意思。點擊后,就出現了右邊那些線程上下文信息了,可以看到有很多的線程,我們主要關注下main線程,線程狀態確實是waiting的,接著點擊箭頭所指向的main線程,可以看到如下內容:

"main@1" prio=5 tid=0x1 nid=NA waiting
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Unsafe.java:-1)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
at org.springframework.boot.autoconfigure.BackgroundPreinitializer.onApplicationEvent(BackgroundPreinitializer.java:63)
at org.springframework.boot.autoconfigure.BackgroundPreinitializer.onApplicationEvent(BackgroundPreinitializer.java:45)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:158)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.boot.context.event.EventPublishingRunListener.finished(EventPublishingRunListener.java:115)
at org.springframework.boot.SpringApplicationRunListeners.callFinishedListener(SpringApplicationRunListeners.java:79)
at org.springframework.boot.SpringApplicationRunListeners.finished(SpringApplicationRunListeners.java:72)
at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:745)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134)
- locked(a java.util.concurrent.atomic.AtomicBoolean)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.bootstrapServiceContext(BootstrapApplicationListener.java:175)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:98)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:64)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:74)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:325)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:296)
at cn.keking.project.customerManagement.KekingCustomerManagement.main(KekingCustomerManagement.java:36)

可以看到是通過CountDownLatch.await()阻塞了線程,接著看下面那行,所在代碼塊如下:

private static final CountDownLatch preinitializationComplete = new CountDownLatch(1);
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
   if (event instanceof ApplicationEnvironmentPreparedEvent) {
      if (preinitializationStarted.compareAndSet(false, true)) {
         performPreinitialization();
      }
   }
   if (event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) {
      try {
         preinitializationComplete.await();
      }
      catch (InterruptedException ex) {
         Thread.currentThread().interrupt();
      }
   }
}

這是spring boot中的一個安全初始化資源的一個類,代碼所示為監聽SpringApplicationEvent事件,可以肯定的是,它的邏輯執行到了 preinitializationComplete.await();這里,導致了線程阻塞了。正常情況下,spring會觸發ApplicationEnvironmentPreparedEvent事件完成資源的初始化,這里先不深究Spring為什么這么做,主要通過程序邏輯看下為什么卡這里了,在preinitializationComplete.await();所在行打個斷點,看下event對象里的信息,如下:

怎么解決spring-boot項目啟動遲緩異常排查的問題

原來event是一個Spring上下文初始化失敗的異常事件對象,對象里包含了具體的異常信息,如箭頭所指,關鍵異常信息如:

NoSuchMethodError:"org.springframework.util.ObjectUtils.

unwrapOptional(Ljava/lang/Object;)Ljava/lang/Object;"

假設問題

通過上面的分析,基本定位到Spring boot應用啟動卡住這個表象背后的真實原因了,而且也定位到了異常信息。

出現NoSuchMethodError異常,是因為調用方法的時候,找不到方法了。一般出現在兩個有關聯的jar包,但是版本對不上了,也就是常說的jar版本依賴沖突。查看了下,ObjectUtils是spring-core包里的一個類,當前的4.1.3版本確實沒有這個unwrapOptional方法,spring-core-5.x的版本才新增了這個方法。因為之前的依賴是沒有問題,為什么現在spring上下文會調用5.x的版本的方法呢?

所以先假設近期有開發在pom.xml里添加了新的的依賴,導致了這個問題。

小心求證

有了找問題的方向就好辦了,因為代碼都是git管理維護的,所以查看下pom.xml文件近期的提交記錄即可,查看后,確實發現了近期對pom.xml有改動,添加了一個依賴:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

這里還涉及到一點Maven依賴優先級的問題,在pom.xml里直接這樣添加的依賴優先于其他jar中pom.xml依賴的,也就是說,即使spring boot1.5.7自帶了Spring-context.4.1.3,但是這樣指定后,應用最后依賴的還是5.1.6的版本。具體的Maven依賴關系,可以參考我的博文《關于Maven的使用,這些你都了解了么?》。結合之前的分析,八九不離十了就是因為加了這個依賴導致的問題,spring-context.5.1.6配合spring-core.4.1.3肯定得出問題啊。直接移除這個依賴,然后啟動系統一切正常,日志打印了Spring加載上線文的信息。

問題總結

定位這個問題的關鍵在于要了解java中線程堆棧的知識,在沒有足夠異常日志情況下通過線程快照排查問題。在定位到問題后,如NoSuchMethodError這樣的異常,需要平時的經驗積累來假設問題的真實原因,然后在追本溯源驗明問題所在根本原因。找問題本質一定要這種循序漸進的思路。舉例,出現這種問題,如果你直接去搜索引擎搜:“Spring boot應用啟動卡住了”,是搜不出來什么東西的,但是當你發現了是由于jar沖突。去搜索引擎搜索:

“NoSuchMethodError:"org.springframework.util.ObjectUtils.

unwrapOptional(Ljava/lang/Object;)Ljava/lang/Object;"”。

就會有很多的內容,很容易解決問題。

關于“怎么解決spring-boot項目啟動遲緩異常排查的問題”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

应用必备| 福清市| 上林县| 策勒县| 正宁县| 镇原县| 普宁市| 宁城县| 青川县| 永济市| 吉水县| 彩票| 启东市| 沁阳市| 馆陶县| 柳州市| 雷山县| 鄂温| 丰原市| 金门县| 射洪县| 双柏县| 高平市| 准格尔旗| 赣榆县| 奈曼旗| 额尔古纳市| 宁城县| 黄骅市| 达尔| 吴川市| 平顶山市| 吉林省| 达孜县| 宜丰县| 西和县| 盐亭县| 新乐市| 彰化县| 平潭县| 拉萨市|