1. 我们先来看看框架会自动注册哪些httpmessageconvert? 在哪个地方开始注册的?
在对mvc:annotation-driven解析的AnnotationDrivenBeanDefinitionParser中,有这么一个方法:
ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
获取所有的HttpMessageConverter,最终设置到RequestMappingHandlerAdapter的private List<HttpMessageConverter<?>> messageConverters属性上。看下具体的获取过程:
private ManagedList<?> getMessageConverters(Element element, Object source, ParserContext parserContext) { Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters"); ManagedList<? super Object> messageConverters = new ManagedList<Object>(); if (convertersElement != null) { messageConverters.setSource(source); for (Element beanElement : DomUtils.getChildElementsByTagName(convertersElement, "bean", "ref")) { Object object = parserContext.getDelegate().parsePropertySubElement(beanElement, null); messageConverters.add(object); } } if (convertersElement == null || Boolean.valueOf(convertersElement.getAttribute("register-defaults"))) { messageConverters.setSource(source); messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source)); RootBeanDefinition stringConverterDef = createConverterDefinition(StringHttpMessageConverter.class, source); stringConverterDef.getPropertyValues().add("writeAcceptCharset", false); messageConverters.add(stringConverterDef); messageConverters.add(createConverterDefinition(ResourceHttpMessageConverter.class, source)); messageConverters.add(createConverterDefinition(SourceHttpMessageConverter.class, source)); messageConverters.add(createConverterDefinition(AllEncompassingFormHttpMessageConverter.class, source)); if (romePresent) { messageConverters.add(createConverterDefinition(AtomFeedHttpMessageConverter.class, source)); messageConverters.add(createConverterDefinition(RssChannelHttpMessageConverter.class, source)); } if (jackson2XmlPresent) { RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2XmlHttpMessageConverter.class, source); GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source); jacksonFactoryDef.getPropertyValues().add("createXmlMapper", true); jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef); messageConverters.add(jacksonConverterDef); } else if (jaxb2Present) { messageConverters.add(createConverterDefinition(Jaxb2RootElementHttpMessageConverter.class, source)); } if (jackson2Present) { RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2HttpMessageConverter.class, source); GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source); jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef); messageConverters.add(jacksonConverterDef); } else if (gsonPresent) { messageConverters.add(createConverterDefinition(GsonHttpMessageConverter.class, source)); } } return messageConverters; }
该过程第一步:
解析并获取我们自定义的HttpMessageConverter,
并在xml中配置
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
该过程第二步:
< mvc:message-converters register-defaults="true">有一个register-defaults属性,当为true时,仍然注册默认的HttpMessageConverter,当为false则不注册,仅仅使用用户自定义的HttpMessageConverter。
获取完毕,便会将这些HttpMessageConverter设置进RequestMappingHandlerAdapter的messageConverters属性中。
2. HttpMessageConvert的使用
举个例子:
@RequestMapping(value="/string", method=RequestMethod.POST) public @ResponseBody String readString(@RequestBody String string) { return "Read string '" + string + "'"; }
在SpringMVC进入readString方法前,会根据@RequestBody注解选择适当的HttpMessageConverter实现类来将请求参数解析到string变量中,具体来说是使用了StringHttpMessageConverter类,它的canRead()方法返回true,然后它的read()方法会从请求中读出请求参数,绑定到readString()方法的string变量中。
当SpringMVC执行readString方法后,由于返回值标识了@ResponseBody,SpringMVC将使用StringHttpMessageConverter的write()方法,将结果作为String值写入响应报文,当然,此时canWrite()方法返回true。