springboot webmvc初始化:一個登錄異常引出的話題

1.場景復現:

一個登錄異常引出的問題。

咱們經過精心組織組件掃描的方式,來裝配不一樣的子模塊,造成一個可運行的應用;java

在載入某個子模塊後,咱們發現應用雖然正常啓動,但嘗試登錄的時候,出現一個很異常的異常,部分stacktrace以下:
 
processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.mobile.device.Device] with root cause

java.lang.NoSuchMethodException: org.springframework.mobile.device.Device.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082) ~[na:1.8.0_171]
	at java.lang.Class.getDeclaredConstructor(Class.java:2178) ~[na:1.8.0_171]
	at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:209) ~[spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:84) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
	at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:132) ~[spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
	at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124) ~[spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
	

異常棧部分調用關係以下:web

 

 

若是移除子模塊,應用啓動後,同一個入口會觸發的正常調用棧以下:spring

 

 

 

換句話說,異常狀況和正常狀況,走了不一樣的處理鏈。安全

 

1.咱們初步懷疑是包衝突,但驗證後排除掉這個問題;

2.而後繼續經過調試代碼,分析發現加入子模塊後,啓動的mvc

HandlerMethodArgumentResolver 實例有27個;

而不加入子模塊,啓動的app

HandlerMethodArgumentResolver 實例有33個,多了幾個resolver,其中包括DeviceHandlerMethodArgumentResolver,看起來找到好的線索了;

 

3.根據線索,懷疑是配置問題,首先懷疑的是安全方面的配置問題;但一直測試分析沒有獲得結果;ide

4.後續,用排除法,發現此模塊中去掉一個定義的配置類,問題就能夠獲得解決,這個配置以下::函數

Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

...測試

}spa

 

 

2.通過全部線索的梳理,這個問題產生的內在機制比較明確了:

 

HandlerMethodArgumentResolver

源碼註釋:
Strategy interface for resolving method parameters into argument values in the context of a given request.

簡單能夠理解爲:解析方法參數的策略接口;通俗的理解爲,(controller的)參數解析(構造)轉換按這個接口來實現;

 

WebMvcConfigurationSupport

源碼註釋:

This is the main class providing the configuration behind the MVC Java config.

其中有一個方法:

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {

簡而言之,DeviceHandlerMethodArgumentResolver 實例是靠

WebMvcConfigurationSupport 提供的機制(模板函數),加載進容器處理鏈的;

 

DelegatingWebMvcConfiguration

 

實際上,spring 依靠 

DelegatingWebMvcConfiguration 自動檢測並代理實現全部的自定義配置
/**
* A subclass of {@code WebMvcConfigurationSupport} that detects and delegates
* to all beans of type {@link WebMvcConfigurer} allowing them to customize the
* configuration provided by {@code WebMvcConfigurationSupport}. This is the
* class actually imported by {@link EnableWebMvc @EnableWebMvc}.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
 

 

WebMvcAutoConfiguration

DelegatingWebMvcConfiguration 的實例建立,是經過下面這個類
WebMvcAutoConfiguration 導入,可是有個條件:當容器內不存在 WebMvcConfigurationSupport 的實例時
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
 
 

因此,當咱們本身子模塊的代碼,有這個自定義配置時

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

系統默認的webmvc 配置行爲將會被覆蓋

相關文章
相關標籤/搜索