SpringMVC source code parsing-message converter HttpMessageConverter,

Source: Internet
Author: User

SpringMVC source code parsing-message converter HttpMessageConverter,

Summary

SpringMVC uses a message converter to automatically convert request messages and objects, objects, and response packets.

In SpringMVC, the @ RequestBody and @ ResponseBody annotations can be used to convert the request message to the object and the object to the Response Message respectively. At the underlying layer, this flexible message conversion mechanism is provided, the newly introduced HttpMessageConverter in Spring3.x is the message converter mechanism.

# The abstraction of the Http request is still returned to the request-response, that is, to parse the Request body, and then return the response message, the most basic Http request process. We know that in the servlet standard, you can use the following methods in the javax. servlet. ServletRequest interface:

public ServletInputStream getInputStream() throws IOException; 

To obtain a ServletInputStream. This ServletInputStream can read all the content of an original request message. Similarly, in the javax. servlet. ServletResponse interface, you can use the following methods:

public ServletOutputStream getOutputStream() throws IOException;

To get a ServletOutputStream. This ServletOutputSteam inherits from the OutputStream in java, allowing you to output Http response packets.

Let's try to think about it like SpringMVC designers. We know that Http requests and response packets are essentially strings. When a request message comes to the java World, it will be encapsulated into a ServletInputStream input stream for us to read packets. The response packet is output through an output stream of ServletOutputStream.

We can only read original string packets from the stream. Similarly, we can only write original characters to the output stream. In the java World, the processing of business logic is based on the processing dimensions of objects with business meanings. Then, when packets reach SpringMVC and spring MVC, there is an impedance problem between a string and a java object. This process cannot be manually converted by developers. We know that in Struts2, OGNL is used to deal with this problem. In SpringMVC, It is the HttpMessageConverter mechanism. Let's look at two interfaces first.

# The HttpInputMessage class is the abstraction of an Http request message in SpringMVC. In the read () method of HttpMessageConverter, there is an HttpInputMessage parameter, it is the internal abstraction of the receptor "Request Message" applied by the message converter of SpringMVC. The message converter extracts messages from the "Request Message" according to rules and converts them to objects declared in method parameters.

package org.springframework.http;import java.io.IOException;import java.io.InputStream;public interface HttpInputMessage extends HttpMessage { InputStream getBody() throws IOException;}

# The HttpOutputMessage class is the abstraction of an Http response packet in SpringMVC. In the write () method of HttpMessageConverter, there is an HttpOutputMessage parameter, it is the internal abstraction of the receptor "Response Message" applied by the message converter of SpringMVC. The message converter writes the "Response Message" to the response message according to certain rules.

package org.springframework.http;import java.io.IOException;import java.io.OutputStream;public interface HttpOutputMessage extends HttpMessage { OutputStream getBody() throws IOException;}

# HttpMessageConverter abstracts the interfaces at the highest level of the message converter and describes the general features of a message converter. We can refer to the methods defined in this interface, to understand how Spring3.x designers think about this mechanism.

package org.springframework.http.converter;import java.io.IOException;import java.util.List;import org.springframework.http.HttpInputMessage;import org.springframework.http.HttpOutputMessage;import org.springframework.http.MediaType;public interface HttpMessageConverter<T> { boolean canRead(Class<?> clazz, MediaType mediaType); boolean canWrite(Class<?> clazz, MediaType mediaType); List<MediaType> getSupportedMediaTypes(); T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;}

The definition of the HttpMessageConverter Interface contains the canRead (), read (), canWrite (), and write () methods. MediaType encapsulates the Media Type attribute of the request. For example, we declare the following processing method.

@RequestMapping(value="/string", method=RequestMethod.POST)public @ResponseBody String readString(@RequestBody String string) { return "Read string '" + string + "'";}

Before SpringMVC enters the readString method, it will select an appropriate HttpMessageConverter implementation Class Based on the @ RequestBody annotation to parse the request parameters to the string variable. Specifically, it uses the StringHttpMessageConverter class, its canRead () method returns true, and its read () method reads the request parameters from the request and binds them to the string variable of the readString () method.

After SpringMVC executes the readString method, because the returned value identifies @ ResponseBody, SpringMVC uses the write () method of StringHttpMessageConverter to write the result as a String value to the response message. Of course, canWrite () returns true.

We can use the figure below to briefly describe this process.

# One Class described in the preceding procedure is org. springframework. web. servlet. mvc. method. annotation. RequestResponseBodyMethodProcessor. This class implements both HandlerMethodArgumentResolver and HandlerMethodReturnValueHandler interfaces. The former is the policy interface that binds the request message to the processing method parameter, and the latter is the policy interface that processes the return value of the processing method. The source code of the two interfaces is as follows:

package org.springframework.web.method.support;import org.springframework.core.MethodParameter;import org.springframework.web.bind.WebDataBinder;import org.springframework.web.bind.support.WebDataBinderFactory;import org.springframework.web.context.request.NativeWebRequest;public interface HandlerMethodArgumentResolver { boolean supportsParameter(MethodParameter parameter); Object resolveArgument(MethodParameter parameter,   ModelAndViewContainer mavContainer,   NativeWebRequest webRequest,   WebDataBinderFactory binderFactory) throws Exception;}package org.springframework.web.method.support;import org.springframework.core.MethodParameter;import org.springframework.web.context.request.NativeWebRequest;public interface HandlerMethodReturnValueHandler { boolean supportsReturnType(MethodParameter returnType); void handleReturnValue(Object returnValue,   MethodParameter returnType,   ModelAndViewContainer mavContainer,   NativeWebRequest webRequest) throws Exception;}

The RequestResponseBodyMethodProcessor class serves both method Parameter Parsing and return value processing. From its source code, we can find the method implementation of the above two interfaces.

Implementation of the HandlerMethodArgumentResolver interface:

public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class);}public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Object argument = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter); WebDataBinder binder = binderFactory.createBinder(webRequest, argument, name); if (argument != null) { validate(binder, parameter); } mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); return argument;}

Implementation of the HandlerMethodReturnValueHandler Interface

public boolean supportsReturnType(MethodParameter returnType) { return returnType.getMethodAnnotation(ResponseBody.class) != null;} public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException { mavContainer.setRequestHandled(true); if (returnValue != null) { writeWithMessageConverters(returnValue, returnType, webRequest); }}

After reading the above Code, the entire HttpMessageConverter message conversion context is very clear. The implementation of the two interfaces is based on whether @ RequestBody and @ ResponseBody are available, and then HttpMessageConverter is called to read and write messages respectively.

If you want to know how to track the RequestResponseBodyMethodProcessor, follow the previous blog posts and download the source code from spring-mvc-showcase, debug the HttpMessageConverter-related examples. As long as you are willing to work hard, I believe you will have your own gains.

# Thinking about the essence of Zhang Xiaolong's talk: "It's just a platform where messages are transferred ". In our SpringMVC source code analysis process, we can understand similar principles from the HttpMessageConverter mechanism. In the eyes of SpringMVC designers, a request message and a response message are abstracted as a request message HttpInputMessage and a response message HttpOutputMessage.

When processing a request, the appropriate message converter binds the request message to a parameter object in the method. Here, the same object may have different message formats, such as json and xml. Similarly, when responding to a request, the return value of the method may also be returned in different message formats, such as json and xml.

In SpringMVC, we have different HttpMessageConverter implementation classes for different message formats. However, as long as the "valid information" contained in these messages is consistent, different message converters will generate the same conversion result. Different parsing details of various messages are blocked in different HttpMessageConverter implementation classes.

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.