一个登录异常引出的问题。
咱们经过精心组织组件扫描的方式,来装配不一样的子模块,造成一个可运行的应用;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 配置行为将会被覆盖;