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 配置行为将会被覆盖

相关文章
相关标签/搜索