激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringMVC源碼解析之消息轉換器HttpMessageConverter

SpringMVC源碼解析之消息轉換器HttpMessageConverter

2021-02-24 13:02相見歡 Java教程

本篇文章主要介紹了SpringMVC源碼解析之消息轉換器HttpMessageConverter ,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

摘要

SpringMVC使用消息轉換器實現請求報文和對象、對象和響應報文之間的自動轉換

在SpringMVC中,可以使用@RequestBody和@ResponseBody兩個注解,分別完成請求報文到對象和對象到響應報文的轉換,底層這種靈活的消息轉換機制,就是Spring3.x中新引入的HttpMessageConverter即消息轉換器機制。

#Http請求的抽象 還是回到請求-響應,也就是解析請求體,然后返回響應報文這個最基本的Http請求過程中來。我們知道,在servlet標準中,可以用javax.servlet.ServletRequest接口中的以下方法:

?
1
public ServletInputStream getInputStream() throws IOException;

來得到一個ServletInputStream。這個ServletInputStream中,可以讀取到一個原始請求報文的所有內容。同樣的,在javax.servlet.ServletResponse接口中,可以用以下方法:

?
1
public ServletOutputStream getOutputStream() throws IOException;

來得到一個ServletOutputStream,這個ServletOutputSteam,繼承自java中的OutputStream,可以讓你輸出Http的響應報文內容。

讓我們嘗試著像SpringMVC的設計者一樣來思考一下。我們知道,Http請求和響應報文本質上都是一串字符串,當請求報文來到java世界,它會被封裝成為一個ServletInputStream的輸入流,供我們讀取報文。響應報文則是通過一個ServletOutputStream的輸出流,來輸出響應報文。

我們從流中,只能讀取到原始的字符串報文,同樣,我們往輸出流中,也只能寫原始的字符。而在java世界中,處理業務邏輯,都是以一個個有業務意義的對象為處理維度的,那么在報文到達SpringMVC和從SpringMVC出去,都存在一個字符串到java對象的阻抗問題。這一過程,不可能由開發者手工轉換。我們知道,在Struts2中,采用了OGNL來應對這個問題,而在SpringMVC中,它是HttpMessageConverter機制。我們先來看兩個接口。

#HttpInputMessage 這個類是SpringMVC內部對一次Http請求報文的抽象,在HttpMessageConverter的read()方法中,有一個HttpInputMessage的形參,它正是SpringMVC的消息轉換器所作用的受體“請求消息”的內部抽象,消息轉換器從“請求消息”中按照規則提取消息,轉換為方法形參中聲明的對象。

?
1
2
3
4
5
6
7
8
9
10
package org.springframework.http;
 
import java.io.IOException;
import java.io.InputStream;
 
public interface HttpInputMessage extends HttpMessage {
 
 InputStream getBody() throws IOException;
 
}

#HttpOutputMessage 這個類是SpringMVC內部對一次Http響應報文的抽象,在HttpMessageConverter的write()方法中,有一個HttpOutputMessage的形參,它正是SpringMVC的消息轉換器所作用的受體“響應消息”的內部抽象,消息轉換器將“響應消息”按照一定的規則寫到響應報文中。

?
1
2
3
4
5
6
7
8
9
10
package org.springframework.http;
 
import java.io.IOException;
import java.io.OutputStream;
 
public interface HttpOutputMessage extends HttpMessage {
 
 OutputStream getBody() throws IOException;
 
}

#HttpMessageConverter 對消息轉換器最高層次的接口抽象,描述了一個消息轉換器的一般特征,我們可以從這個接口中定義的方法,來領悟Spring3.x的設計者對這一機制的思考過程。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;
 
}

HttpMessageConverter接口的定義出現了成對的canRead(),read()和canWrite(),write()方法,MediaType是對請求的Media Type屬性的封裝。舉個例子,當我們聲明了下面這個處理方法。

?
1
2
3
4
@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。

我們可以用下面的圖,簡單描述一下這個過程。

SpringMVC源碼解析之消息轉換器HttpMessageConverter

#RequestResponseBodyMethodProcessor 將上述過程集中描述的一個類是org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor,這個類同時實現了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler兩個接口。前者是將請求報文綁定到處理方法形參的策略接口,后者則是對處理方法返回值進行處理的策略接口。兩個接口的源碼如下:

?
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
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;
 
}

RequestResponseBodyMethodProcessor這個類,同時充當了方法參數解析和返回值處理兩種角色。我們從它的源碼中,可以找到上面兩個接口的方法實現。

對HandlerMethodArgumentResolver接口的實現:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}

對HandlerMethodReturnValueHandler接口的實現

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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);
 }
}

看完上面的代碼,整個HttpMessageConverter消息轉換的脈絡已經非常清晰。因為兩個接口的實現,分別是以是否有@RequestBody和@ResponseBody為條件,然后分別調用HttpMessageConverter來進行消息的讀寫。

如果你想問,怎么樣跟蹤到RequestResponseBodyMethodProcessor中,請你按照前面幾篇博文的思路,然后到這里spring-mvc-showcase下載源碼回來,對其中HttpMessageConverter相關的例子進行debug,只要你肯下功夫,相信你一定會有屬于自己的收獲的。

#思考 張小龍在談微信的本質時候說:“微信只是個平臺,消息在其中流轉”。在我們對SpringMVC源碼分析的過程中,我們可以從HttpMessageConverter機制中領悟到類似的道理。在SpringMVC的設計者眼中,一次請求報文和一次響應報文,分別被抽象為一個請求消息HttpInputMessage和一個響應消息HttpOutputMessage。

處理請求時,由合適的消息轉換器將請求報文綁定為方法中的形參對象,在這里,同一個對象就有可能出現多種不同的消息形式,比如json和xml。同樣,當響應請求時,方法的返回值也同樣可能被返回為不同的消息形式,比如json和xml。

在SpringMVC中,針對不同的消息形式,我們有不同的HttpMessageConverter實現類來處理各種消息形式。但是,只要這些消息所蘊含的“有效信息”是一致的,那么各種不同的消息轉換器,都會生成同樣的轉換結果。至于各種消息間解析細節的不同,就被屏蔽在不同的HttpMessageConverter實現類中了。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://my.oschina.net/lichhao/blog/172562

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久国产精 | 天天草天天干天天射 | 成人国产精品一区 | 久久中文免费 | av在线日韩 | 亚洲精品久久久久久久久久 | 国产精品久久久麻豆 | 狠狠干五月天 | 日韩黄色av| 三人弄娇妻高潮3p视频 | 久久av免费 | 欧美高清另类自拍视频在线看 | 香蕉成人在线视频 | 久久久综合 | 黄色久 | 国产一级在线观看视频 | 宅男噜噜噜66国产在线观看 | a一级黄色毛片 | av电影在线播放 | 蜜桃传媒视频麻豆第一区免费观看 | 中文字幕在线观看亚洲 | 国产资源视频在线观看 | 72pao成人国产永久免费视频 | 蜜桃精品视频在线观看 | 毛片a片免费看 | 一级毛片播放 | 久久国产成人午夜av浪潮 | 欧美成人激情 | 黄色高清视频网站 | 成人毛片网 | 色中色在线视频 | 中文字幕在线一 | h色网站免费观看 | 毛片免费试看 | 久久久久久久久久久国产精品 | 中文字幕一区在线观看视频 | 欧美一级三级在线观看 | 中文有码一区二区 | 国产精品亚洲yourport | 国产精品刺激对白麻豆99 | 91色爱 |