一個登錄異常引出的問題。
咱們經過精心組織組件掃描的方式,來裝配不一樣的子模塊,造成一個可運行的應用;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
HandlerMethodArgumentResolver
源碼註釋:
Strategy interface for resolving method parameters into argument values in the context of a given request.
簡單能夠理解爲:解析方法參數的策略接口;通俗的理解爲,(controller的)參數解析(構造)轉換按這個接口來實現;
源碼註釋:
This is the main class providing the configuration behind the MVC Java config.
其中有一個方法:
@Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { |
簡而言之,DeviceHandlerMethodArgumentResolver 實例是靠
WebMvcConfigurationSupport 提供的機制(模板函數),加載進容器處理鏈的;
實際上,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 {
DelegatingWebMvcConfiguration 的實例建立,是經過下面這個類
WebMvcAutoConfiguration 導入,可是有個條件:當容器內不存在 WebMvcConfigurationSupport 的實例時
因此,當咱們本身子模塊的代碼,有這個自定義配置時
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
系統默認的webmvc 配置行爲將會被覆蓋;