springboot2.x中springmvc对于http消息进行序列化和反序列化的核心是HttpMessageConverter(消息转换器),对于JSON格式数据转换,Spring默认采用MappingJackson2HttpMessageConverter,Springboot会将MappingJackson2HttpMessageConverter自动装载到IOC容器中。
@Configuration(proxyBeanMethods = false)
class JacksonHttpMessageConvertersConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnBean(ObjectMapper.class)
@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY,
havingValue = "jackson", matchIfMissing = true)
static class MappingJackson2HttpMessageConverterConfiguration {
@Bean
@ConditionalOnMissingBean(value = MappingJackson2HttpMessageConverter.class,
ignoredType = {
"org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter",
"org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter" })
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
return new MappingJackson2HttpMessageConverter(objectMapper);
}
}
.......
}
其中ObjectMapper是Spring容器中的bean,当没有自定义配置ObjectMapper时,会自动注入IOC容器。当需要自定义序列化/反序列化的配置时,就需要对ObjectMapper进行配置。
@Configuration(proxyBeanMethods = false) // 当引入了Jackson的包,可以找到ObjectMapper.class这个类,才会构建Bean @ConditionalOnClass(ObjectMapper.class) public class JacksonAutoConfiguration { private static final Map<?, Boolean> FEATURE_DEFAULTS; static { Map<Object, Boolean> featureDefaults = new HashMap<>(); // Date类型默认默认不会转换为时间戳类型 featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults); } @Bean public JsonComponentModule jsonComponentModule() { return new JsonComponentModule(); } @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Jackson2ObjectMapperBuilder.class) static class JacksonObjectMapperConfiguration { @Bean @Primary // 当容器中不存在ObjectMapper 这个Bean,才会生成默认Bean,故当自定义了ObjectMapper到容器中,默认配置不会生效 @ConditionalOnMissingBean ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { return builder.createXmlMapper(false).build(); } }
......
}
我们使用的@RequestBody和@ResponseBoby注解,作用就是将报文反序列化/序列化POJO对象
在请求时SpringMVC
会在请求头中寻找contentType
参数,然后去匹配能够处理这种类型的消息转换器。而在返回数据时,SpringMVC
根据请求头的Accept
属性,再将对象转换成响应报文。
SpringBoot2.x自动装载MappingJackson2HttpMessageConvereter消息转换器,MappingJacson2HttpMessageConverter会获取容器中ObjectMapper的配置,来进行Jackson的序列化和反序列化。ObjectMapper时JSON操作的核心,Jackson的JSON操作都是通过ObjectMapper实现的。
注:SpringBoot2.x中不要将自定义的PObjectMapper对象放入Spring容器中,否则会导致默认的ObejctMapper配置被覆盖掉。
SpringBoot2.x可以通过yaml文件只用sprig.jackson为前缀的配置修改ObjectMapper,也可以通过Jackson2ObjectMapperBuilderCustomizer接口代码修改ObjectMapper配置。
@Configuration(proxyBeanMethods = false) @ConditionalOnClass(Jackson2ObjectMapperBuilder.class) static class JacksonObjectMapperBuilderConfiguration { @Bean @Scope("prototype") @ConditionalOnMissingBean Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(ApplicationContext applicationContext, List<Jackson2ObjectMapperBuilderCustomizer> customizers) { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.applicationContext(applicationContext); customize(builder, customizers); return builder; } private void customize(Jackson2ObjectMapperBuilder builder, List<Jackson2ObjectMapperBuilderCustomizer> customizers) { for (Jackson2ObjectMapperBuilderCustomizer customizer : customizers) { customizer.customize(builder); } } } @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Jackson2ObjectMapperBuilder.class) @EnableConfigurationProperties(JacksonProperties.class) static class Jackson2ObjectMapperBuilderCustomizerConfiguration { @Bean StandardJackson2ObjectMapperBuilderCustomizer standardJacksonObjectMapperBuilderCustomizer( ApplicationContext applicationContext, JacksonProperties jacksonProperties) { return new StandardJackson2ObjectMapperBuilderCustomizer(applicationContext, jacksonProperties); } static final class StandardJackson2ObjectMapperBuilderCustomizer implements Jackson2ObjectMapperBuilderCustomizer, Ordered { private final ApplicationContext applicationContext; private final JacksonProperties jacksonProperties; StandardJackson2ObjectMapperBuilderCustomizer(ApplicationContext applicationContext, JacksonProperties jacksonProperties) { this.applicationContext = applicationContext; this.jacksonProperties = jacksonProperties; } @Override public int getOrder() { return 0; } @Override public void customize(Jackson2ObjectMapperBuilder builder) { if (this.jacksonProperties.getDefaultPropertyInclusion() != null) { builder.serializationInclusion(this.jacksonProperties.getDefaultPropertyInclusion()); } if (this.jacksonProperties.getTimeZone() != null) { builder.timeZone(this.jacksonProperties.getTimeZone()); } configureFeatures(builder, FEATURE_DEFAULTS); configureVisibility(builder, this.jacksonProperties.getVisibility()); configureFeatures(builder, this.jacksonProperties.getDeserialization()); configureFeatures(builder, this.jacksonProperties.getSerialization()); configureFeatures(builder, this.jacksonProperties.getMapper()); configureFeatures(builder, this.jacksonProperties.getParser()); configureFeatures(builder, this.jacksonProperties.getGenerator()); configureDateFormat(builder); configurePropertyNamingStrategy(builder); configureModules(builder); configureLocale(builder); }
......
}