架构
HttpMessageConverter接口
名称
ByteArrayHttpMessageConverter
FormHttpMessageConverter
XmlAwareFormHttpMessageConverter
ResourceHttpMessageConverter
SourceHttpMessageConverter
StringHttpMessageConverter
SimpleXmlHttpMessageConverter
MappingJackson2HttpMessageConverter
GsonHttpMessageConverter
SyndFeedHttpMessageConverter
RssChannelHttpMessageConverter
AtomFeedHttpMessageConverter
具体功能见 RestTemplate Module
想研究源码的可以从最简单的 StringHttpMessageConverter
看起
Spring调用过程 在DispatcherServlet初始化的过程会调用一个叫做initHandlerAdapters
的方法, 该方法内部会扫描容器中所有的类,以及他们的父类,找到所有实现了HandlerAdapter
接口的类, 并将他们注册到DispatcherServlet
的HandlerAdapters
中。
如果没有扫描到的HandlerAdapter,这个方法会加载一些默认的HandlerAdapter。
The default implementation uses the “DispatcherServlet.properties” file (in the same package as the DispatcherServlet class) to determine the class names.
Spring 4.3.2 中有一个实现了HandlerAdapter
接口的类会被扫描到,这个类叫做RequestMappingHandlerAdapter
RequestMappingHandlerAdapter 这个类在构造的时候就加载了许多messageConverter
1 2 3 4 5 6 7 8 9 10 public RequestMappingHandlerAdapter () { StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); stringHttpMessageConverter.setWriteAcceptCharset(false ); this .messageConverters = new ArrayList<HttpMessageConverter<?>>(4 ); this .messageConverters.add(new ByteArrayHttpMessageConverter()); this .messageConverters.add(stringHttpMessageConverter); this .messageConverters.add(new SourceHttpMessageConverter<Source>()); this .messageConverters.add(new AllEncompassingFormHttpMessageConverter()); }
其中AllEncompassingFormHttpMessageConverter
继承自FormHttpMessageConverter
, 它有一个变量叫做partConverters
,存储了一系列的HttpMessageConverter
1 2 3 4 5 6 7 8 9 10 private List<HttpMessageConverter<?>> partConverters = new ArrayList<HttpMessageConverter<?>>();public FormHttpMessageConverter () { this .supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); this .supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA); this .partConverters.add(new ByteArrayHttpMessageConverter()); StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); stringHttpMessageConverter.setWriteAcceptCharset(false ); this .partConverters.add(stringHttpMessageConverter); this .partConverters.add(new ResourceHttpMessageConverter()); }
在AllEncompassingFormHttpMessageConverter
中又根据classPath中是否包含jackson、Gson等jar包来动态的 注册了一些HttpMessageConverter
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConverter { private static final boolean jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder" , AllEncompassingFormHttpMessageConverter.class .getClassLoader ()) ; private static final boolean jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper" , AllEncompassingFormHttpMessageConverter.class .getClassLoader ()) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", AllEncompassingFormHttpMessageConverter.class.getClassLoader()); private static final boolean jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper" , AllEncompassingFormHttpMessageConverter.class .getClassLoader ()) ; private static final boolean gsonPresent = ClassUtils.isPresent("com.google.gson.Gson" , AllEncompassingFormHttpMessageConverter.class .getClassLoader ()) ; public AllEncompassingFormHttpMessageConverter () { addPartConverter(new SourceHttpMessageConverter<Source>()); if (jaxb2Present && !jackson2Present) { addPartConverter(new Jaxb2RootElementHttpMessageConverter()); } if (jackson2Present) { addPartConverter(new MappingJackson2HttpMessageConverter()); } else if (gsonPresent) { addPartConverter(new GsonHttpMessageConverter()); } if (jackson2XmlPresent) { addPartConverter(new MappingJackson2XmlHttpMessageConverter()); } } }
至于这些转换器是怎么使用的,要看RequestMappingHandlerAdapter
中的getDefaultArgumentResolver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers () { List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false )); resolvers.add(new RequestParamMapMethodArgumentResolver()); resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new PathVariableMapMethodArgumentResolver()); resolvers.add(new MatrixVariableMethodArgumentResolver()); resolvers.add(new MatrixVariableMapMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false )); resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this .requestResponseBodyAdvice)); resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this .requestResponseBodyAdvice)); resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this .requestResponseBodyAdvice)); resolvers.add(new RedirectAttributesMethodArgumentResolver()); resolvers.add(new ModelMethodProcessor()); resolvers.add(new MapMethodProcessor()); resolvers.add(new ErrorsMethodArgumentResolver()); resolvers.add(new SessionStatusMethodArgumentResolver()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); if (getCustomArgumentResolvers() != null ) { resolvers.addAll(getCustomArgumentResolvers()); } resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true )); resolvers.add(new ServletModelAttributeMethodProcessor(true )); return resolvers; }
可以看到所有的Converter最终作为一个构造参数传入了RequestResponseBodyMethodProcessor
和RequestPartMethodArgumentResolver
。 前者其实是负责处理@RequestBody
和@ResponseBody
的, 后者则是处理@RequestPart
这个注解的。拿RequestResponseBodyMethodProcessor
为例来看。
这个类的父类实现了HandlerMethodReturnValueHandler
接口,这个接口的作用对照上面的系统整体架构图 可知,是处理Controller返回的结果值的,看其handleReturnValue
方法 。
1 2 3 4 5 6 7 8 @Override public void handleReturnValue (Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true ); writeWithMessageConverters(returnValue, returnType, webRequest); }
首先标记这个请求已经处理过了,然后调用了一个内部方法,从名字就可以看出来,是使用MessageConverter进行 转换。
1 2 3 4 5 6 7 8 9 10 11 protected <T> void writeWithMessageConverters (T returnValue, MethodParameter returnType, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
真正的逻辑还是内部的`writeWithMessageConveters()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 @SuppressWarnings ("unchecked" ) protected <T> void writeWithMessageConverters (T returnValue, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { Class<?> returnValueClass = getReturnValueType(returnValue, returnType); Type returnValueType = getGenericType(returnType); HttpServletRequest servletRequest = inputMessage.getServletRequest(); List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest); List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass, returnValueType); if (returnValue != null && producibleMediaTypes.isEmpty()) { throw new IllegalArgumentException("No converter found for return value of type: " + returnValueClass); } Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>(); for (MediaType requestedType : requestedMediaTypes) { for (MediaType producibleType : producibleMediaTypes) { if (requestedType.isCompatibleWith(producibleType)) { compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType)); } } } if (compatibleMediaTypes.isEmpty()) { if (returnValue != null ) { throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes); } return ; } List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes); MediaType.sortBySpecificityAndQuality(mediaTypes); MediaType selectedMediaType = null ; for (MediaType mediaType : mediaTypes) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break ; } else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break ; } } if (selectedMediaType != null ) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> messageConverter : this .messageConverters) { if (messageConverter instanceof GenericHttpMessageConverter) { if (((GenericHttpMessageConverter<T>) messageConverter).canWrite(returnValueType, returnValueClass, selectedMediaType)) { returnValue = (T) getAdvice().beforeBodyWrite(returnValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage); if (returnValue != null ) { addContentDispositionHeader(inputMessage, outputMessage); ((GenericHttpMessageConverter<T>) messageConverter).write(returnValue, returnValueType, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]" ); } } return ; } } else if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { returnValue = (T) getAdvice().beforeBodyWrite(returnValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage); if (returnValue != null ) { addContentDispositionHeader(inputMessage, outputMessage); ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]" ); } } return ; } } } if (returnValue != null ) { throw new HttpMediaTypeNotAcceptableException(this .allSupportedMediaTypes); } }
至此,HttpMessageConverter如何工作的就真相大白了。
参考链接
SpringMVC关于json、xml自动转换的原理研究(附带源码分析)