架构
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,存储了一系列的HttpMessageConverter1 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自动转换的原理研究(附带源码分析)