記 storm-starter 在某知名 IDE 下的悲催除錯經歷

foreach_break發表於2015-07-14

背景

最近收到這樣一個問題:

Storm處理訊息時會根據Topology生成一棵訊息樹,Storm如何跟蹤每個訊息、如何保證訊息不丟失以及如何實現重發訊息機制?

雖已回覆,但心想還是看下storm這塊的原始碼吧.那看靜態多不爽啊,那總得除錯吧,好吧,造個本地環境來調吧。

先看看maven的build過不過:

搞定storm的編譯打包,接著是storm-starter的編譯打包,一切很順利啊,跑一下看看:

順利出結果了,不就是個hello world嘛!

接著造本地環境吧,將storm-starter的原始碼按maven方式匯入Intellij IDEA,注意,從這時候悲催就開始了。

 

hello,world 打臉了

匯入IDE後,興致勃勃的點了F5,然後:

這尼瑪,說好不打臉的!

看了又看依賴“都合適”啊,ClassPath“都合適”啊,否則編譯不通過啊,為毛跑!不!起!來!

這同樣的操作,在eclipse裡妥妥的啊,各種能跑啊,為毛在Intellij IDEA裡出錯了呢?

 

異常是如何產生的

好吧,既然打臉了,又是知名IDE的粉絲,堅決要知恥而後勇的。

那麼,看下異常如何產生的吧。

(檢視大圖)

上面的圖,基本概括了異常NoClassDefFound產生的路徑。

更細節的異常產生情況如下:

(檢視大圖)

注意看呼叫棧:

  • JVM_GetClassDelaredMethods是JVM內方法,在找入口函式main的過程中,此方法被呼叫。
  • 接著,此方法會呼叫驗證位元組碼的過程:verify_code。
  • 發現有用到backtype.storm.topology.IRichBolt介面,那麼找找這個介面所在的.class檔案吧:如果我們執行java -cp . xxx,通過-cp或者-classpath引數指定了classpath,那麼這個.class就會被找到。然後進入parse的過程。
  • 悲催的是,IDEA的執行或者除錯命令f5->run,沒有將backtype/storm/topology/IRichBolt所在的jar包storm-core.jar加入classpath,這都是後話了…

那麼,既然有個找*.class的過程,這個過程如下:

(檢視大圖)

對上圖做一點簡要說明:

  1. 執行java -cp . $mainClass .
  2. java程式(這裡指java這個程式本身)的入口函式main,會建立虛擬機器JVM例項,過程中會初始化JVM本地ClassLoader.
  3. 在JVM尋找.class檔案時,呼叫ClassLoader::load_classfile方法,從jar包、zip包、目錄中尋找指定的.class檔案 .
  4. 本文中,木有找到backtype/storm/topology/IRichBolt.class,所以會置一個延時異常__pending_exception,這個異常關聯了這個類(介面)、檔名、異常的型別(NoClassDefFound),那這個異常什麼時候處理呢?後文再說.

看下這個異常的內容:

 

異常是如何處理的

好了,異常的產生清楚了,還有個問題,那個__pending_exception是何時被處理呢?

看下圖:

(檢視大圖)

對上圖做下簡要說明:

  1. 執行java -cp . $mainClass .
  2. java程式的入口函式main,在層層初始化的過程中,會呼叫到LoadMainClass函式, 結合本文的第一幅圖就可以知道,這個函式最終會製造那個NoClassDefFound的異常__pending_exception,然後返回的是一個空的mainClass.
  3. 緊跟著LoadMainClass函式,是一個CHECK_EXCEPTION_NULL_LEAVE的巨集,這個巨集展開後,會處理上面製造的那個異常,然後,列印異常資訊。這裡就是那個被打臉的異常了。

 

為什麼被打了臉

這裡,異常產生的本質和異常處理,清楚了。

簡單的概括下就是:

但是,Intellij IDEA為何在執行時不將storm-core.jar包含進classpath呢?

換句話說:為啥被打臉??

(檢視大圖)

打臉的理由很簡單:

  1. F5->run,先make/compile/build,再執行.
  2. 依賴的scope設為了provided,此設定僅在編譯階段將依賴的jar包加入classpath,在執行階段,不會將jar包加入classpath.

解決的方法也非常簡單:

如果不是通過mvn來執行,而是在IDE下除錯/執行,趕緊將依賴的jar包的scope選為compile吧,妥妥的不會被打臉!

看下是不是妥妥的呢?

 

後記

相關文章