今天遇到了一個錯誤,一般的錯誤提示會很明顯,一看就知道是什麼問題。今天遇到的這個說實話真的不好找原因,一般在這種情況下該怎麼解決呢?
分享下我的思路吧,不一定是最好的,至少有用。
直接上圖吧,下面是報錯資訊:
為了方便檢視,我把最重要的資訊提取出來,如下:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [com/cxytiandi/kitty/web/config/WebAppConfigurer.class]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
java.lang.ArrayStoreException這個確實平時很少遇到,看了下原始碼,這個是陣列儲存異常。比如下圖中我框起來的部分就清楚的表示了在什麼場景下會出現這個異常。
也就是在儲存的時候型別不一致,然後就報錯了唄!
第二個需要關注的錯誤資訊是WebAppConfigurer.class,這個還算挺明確的,告訴我哪個類有問題,然後我看了下對應的程式碼,也就手動的對映了資源路徑而已。
於是我就想,是不是這裡面哪個類載入的時候出問題了,我把WebAppConfigurer直接去掉了,但是並沒什麼用,後面還是報的相同的錯誤,只不過是提示另一個類了,就是WebMvcAutoConfiguration。
[org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
所以說這些錯誤資訊沒能直接定位問題就是這個原因,我們要關注的還是java.lang.ArrayStoreException這個異常,只要找到這個異常發生的地方就能解決了。
下面只能藉助於IDEA強大的除錯功能了,增加一個Java Exception Breakpoints了。
然後debug模式重啟,果不其然就報錯的時候就進斷點了。
這下終於找到原因了,parseClassValue的時候出問題了,Class就是 org.springframework.cloud.sleuth.instrument.web.client.feign.TraceFeignClientAutoConfiguration。
這個類是我當時在Sleuth中擴充套件Sentinel對Feign支援的時候做了一些修改,沒想到居然出了Bug。
下面給大家說明下真正的原因吧,在這個擴充套件模組中sentinel的依賴是可選的,如下:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel</artifactId>
<optional>true</optional>
</dependency>
剛好報錯的專案中不需要用到Sentinel,但是用到了Sleuth和Feign,所以TraceFeignClientAutoConfiguration生效了。主要還是Conditional都滿足條件了。
專案中又沒顯示指定依賴Sentinel,這個類自然載入失敗。
所以解決辦法就是要麼加Sentinel依賴,要麼就是在@ConditionalOnClass中加上Sentinel的類,這樣只有當在Sentinel的類在classpath中存在的時候才會載入,如果專案沒依賴Sentinel那麼就不載入,這樣就沒問題了。
最後總結下吧,主要還是要找到真正問題發生在什麼地方,有的時候異常資訊給出的並不一定是真正的地方,只是有關聯而已。
當你封裝的模組設定了optional=true的時候,在對應的配置類載入生效也需要用@ConditionalOnClass來進行判斷啟用,否則就會出現上面的問題。