慎用@EnableWebMvc注解

同事合了代码到开发分支,并没有涉及到改动的类却报错。错误信息如下:

java 复制代码
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; 
nested exception is org.springframework.http.converter.HttpMessageConversionException: 
Type definition error: [simple type, class com.tongweb.demo.bean.Registration];
nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `com.tongweb.demo.bean.Registration` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

这个错误的大概意思就是jackson解析Registration类时出现了错误,说Registration类缺少默认构造函数。这个类是Controller中一个方法的入参。示例代码如下:

java 复制代码
@PostMapping(path = "/instances", consumes = MediaType.APPLICATION_JSON_VALUE)  
public String register(@RequestBody Registration registration) {  
    Registration withSource = Registration.copyOf(registration).source("http-api").build(); 
    return withSource.toString();  
}

相关代码并不涉及到改动,自从我同事代码合过来就开始报错,很不应该。起初我猜测是某些jar冲突引起的。但是查看了他合并过来的代码,也并未涉及到jar依赖的升级变更等。对于这个错误网上是有很多解决方案的,比如加个构造函数。但是不排查到导致问题的原因,这总归是个雷。于是我开启了漫长的排除过程。

首先考虑是jar冲突导致。我重新写了一个新项目,沿用了我目前的所有jar。访问instances接口,jackson解析并不会报错。那只有跟踪源码了。

spring提供了一个Jackson的HTTP消息转换器的配置JacksonHttpMessageConvertersConfiguration,会创建一个MappingJackson2HttpMessageConverterMappingJackson2HttpMessageConverter会负责解析Registration类。特别说明Registration类只有有参构造函数,没有无参构造函数。

HttpMessageConverters负责管理Spring Boot应用程序中使用的HttpMessageConverters。提供了一种向web应用程序添加和合并其他HttpMessageConverter的方便方法。 如果需要,可以向特定的附加转换器注册此bean的实例,否则将使用默认转换器。说白了就是Spring Boot应用程序中的各个转换就是在HttpMessageConverters中。

按理来说MappingJackson2HttpMessageConverter也是HttpMessageConverters中的一员。但是我跟踪源码发现MappingJackson2HttpMessageConverter并未出现在HttpMessageConverters中。跟踪源码WebMvcConfigurationSupport类,源码如下:

java 复制代码
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {  
    messageConverters.add(new ByteArrayHttpMessageConverter());  
    messageConverters.add(new StringHttpMessageConverter());  
    messageConverters.add(new ResourceHttpMessageConverter());  
    messageConverters.add(new ResourceRegionHttpMessageConverter());
    ...
}

这一段关键代码是把HttpMessageConverters添加到messageConverters。后续解析@RequestBody修饰的类就会从中选择对应的Converter。当源码进行到这一步的时候。我发现MappingJackson2HttpMessageConverter并不存在。它的加载顺序发生在了addDefaultHttpMessageConverters方法执行之后。这就导致messageConverters中并没有MappingJackson2HttpMessageConverter。所以当@RequestBody修饰的类没有无参构造函数的时候解析就报错了。一个正常的应用程序MappingJackson2HttpMessageConverter会优先被加载。找到问题的原因就方便多了。

为什么JacksonHttpMessageConvertersConfiguration的加载顺序会晚于WebMvcConfigurationSupport类呢?换而言之有哪些因素会影响WebMvcConfigurationSupport类的加载。答案就是@EnableWebMvc注解!!

如果在代码中使用了@EnableWebMvc注解,那么WebMvcConfigurationSupport就会比JacksonHttpMessageConvertersConfiguration优先加载,因为@EnableWebMvc注解会导入DelegatingWebMvcConfiguration类,而这个类继承了WebMvcConfigurationSupport类,并且有@Order注解,指定了加载顺序。

这样的话,Spring Boot的默认MVC配置就会被关闭,你需要自己配置Spring MVC的功能,例如拦截器、视图解析器、消息转换器等。

相关推荐
2401_8576226623 分钟前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_8575893627 分钟前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
哎呦没2 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
编程、小哥哥2 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
IT学长编程3 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
杨哥带你写代码3 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
A尘埃4 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-23074 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端
代码之光_19804 小时前
SpringBoot校园资料分享平台:设计与实现
java·spring boot·后端
苹果醋36 小时前
快速玩转 Mixtral 8x7B MOE大模型!阿里云机器学习 PAI 推出最佳实践
spring boot·nginx·毕业设计·layui·课程设计