最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringMVC源碼解析之消息轉(zhuǎn)換器HttpMessageConverter

 更新時(shí)間:2017年11月30日 09:09:53   作者:相見歡  
本篇文章主要介紹了SpringMVC源碼解析之消息轉(zhuǎn)換器HttpMessageConverter ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

摘要

SpringMVC使用消息轉(zhuǎn)換器實(shí)現(xiàn)請求報(bào)文和對象、對象和響應(yīng)報(bào)文之間的自動(dòng)轉(zhuǎn)換

在SpringMVC中,可以使用@RequestBody和@ResponseBody兩個(gè)注解,分別完成請求報(bào)文到對象和對象到響應(yīng)報(bào)文的轉(zhuǎn)換,底層這種靈活的消息轉(zhuǎn)換機(jī)制,就是Spring3.x中新引入的HttpMessageConverter即消息轉(zhuǎn)換器機(jī)制。

#Http請求的抽象 還是回到請求-響應(yīng),也就是解析請求體,然后返回響應(yīng)報(bào)文這個(gè)最基本的Http請求過程中來。我們知道,在servlet標(biāo)準(zhǔn)中,可以用javax.servlet.ServletRequest接口中的以下方法:

public ServletInputStream getInputStream() throws IOException; 

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

public ServletOutputStream getOutputStream() throws IOException;

來得到一個(gè)ServletOutputStream,這個(gè)ServletOutputSteam,繼承自java中的OutputStream,可以讓你輸出Http的響應(yīng)報(bào)文內(nèi)容。

讓我們嘗試著像SpringMVC的設(shè)計(jì)者一樣來思考一下。我們知道,Http請求和響應(yīng)報(bào)文本質(zhì)上都是一串字符串,當(dāng)請求報(bào)文來到j(luò)ava世界,它會(huì)被封裝成為一個(gè)ServletInputStream的輸入流,供我們讀取報(bào)文。響應(yīng)報(bào)文則是通過一個(gè)ServletOutputStream的輸出流,來輸出響應(yīng)報(bào)文。

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

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

package org.springframework.http;

import java.io.IOException;
import java.io.InputStream;

public interface HttpInputMessage extends HttpMessage {

 InputStream getBody() throws IOException;

}

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

package org.springframework.http;

import java.io.IOException;
import java.io.OutputStream;

public interface HttpOutputMessage extends HttpMessage {

 OutputStream getBody() throws IOException;

}

#HttpMessageConverter 對消息轉(zhuǎn)換器最高層次的接口抽象,描述了一個(gè)消息轉(zhuǎn)換器的一般特征,我們可以從這個(gè)接口中定義的方法,來領(lǐng)悟Spring3.x的設(shè)計(jì)者對這一機(jī)制的思考過程。

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接口的定義出現(xiàn)了成對的canRead(),read()和canWrite(),write()方法,MediaType是對請求的Media Type屬性的封裝。舉個(gè)例子,當(dāng)我們聲明了下面這個(gè)處理方法。

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

在SpringMVC進(jìn)入readString方法前,會(huì)根據(jù)@RequestBody注解選擇適當(dāng)?shù)腍ttpMessageConverter實(shí)現(xiàn)類來將請求參數(shù)解析到string變量中,具體來說是使用了StringHttpMessageConverter類,它的canRead()方法返回true,然后它的read()方法會(huì)從請求中讀出請求參數(shù),綁定到readString()方法的string變量中。

當(dāng)SpringMVC執(zhí)行readString方法后,由于返回值標(biāo)識了@ResponseBody,SpringMVC將使用StringHttpMessageConverter的write()方法,將結(jié)果作為String值寫入響應(yīng)報(bào)文,當(dāng)然,此時(shí)canWrite()方法返回true。

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

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

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這個(gè)類,同時(shí)充當(dāng)了方法參數(shù)解析和返回值處理兩種角色。我們從它的源碼中,可以找到上面兩個(gè)接口的方法實(shí)現(xiàn)。

對HandlerMethodArgumentResolver接口的實(shí)現(xiàn):

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接口的實(shí)現(xiàn)

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

看完上面的代碼,整個(gè)HttpMessageConverter消息轉(zhuǎn)換的脈絡(luò)已經(jīng)非常清晰。因?yàn)閮蓚€(gè)接口的實(shí)現(xiàn),分別是以是否有@RequestBody和@ResponseBody為條件,然后分別調(diào)用HttpMessageConverter來進(jìn)行消息的讀寫。

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

#思考 張小龍?jiān)谡勎⑿诺谋举|(zhì)時(shí)候說:“微信只是個(gè)平臺(tái),消息在其中流轉(zhuǎn)”。在我們對SpringMVC源碼分析的過程中,我們可以從HttpMessageConverter機(jī)制中領(lǐng)悟到類似的道理。在SpringMVC的設(shè)計(jì)者眼中,一次請求報(bào)文和一次響應(yīng)報(bào)文,分別被抽象為一個(gè)請求消息HttpInputMessage和一個(gè)響應(yīng)消息HttpOutputMessage。

處理請求時(shí),由合適的消息轉(zhuǎn)換器將請求報(bào)文綁定為方法中的形參對象,在這里,同一個(gè)對象就有可能出現(xiàn)多種不同的消息形式,比如json和xml。同樣,當(dāng)響應(yīng)請求時(shí),方法的返回值也同樣可能被返回為不同的消息形式,比如json和xml。

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java ArrayList集合詳解(Java動(dòng)態(tài)數(shù)組)

    Java ArrayList集合詳解(Java動(dòng)態(tài)數(shù)組)

    這篇文章主要介紹了Java ArrayList集合詳解(Java動(dòng)態(tài)數(shù)組),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Spring?Boot虛擬線程Webflux在JWT驗(yàn)證和MySQL查詢性能比較

    Spring?Boot虛擬線程Webflux在JWT驗(yàn)證和MySQL查詢性能比較

    這篇文章主要為大家介紹了Spring Boot虛擬線程與Webflux在JWT驗(yàn)證和MySQL查詢上的性能比較,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 關(guān)于idea中ssm框架的編碼問題分析

    關(guān)于idea中ssm框架的編碼問題分析

    在實(shí)際開發(fā)中需要將操作系統(tǒng)編碼、文件編碼、頁面編碼以及tomcat服務(wù)器編碼保持一致,而tomcat在默認(rèn)情況下是使用UTF-8,這就使得其打印的日志文件出現(xiàn)中文亂碼,因此在一般情況下,只需要將tomcat服務(wù)器的編碼改為GBK即可
    2021-06-06
  • SpringBoot配置actuator的代碼

    SpringBoot配置actuator的代碼

    這篇文章主要介紹了SpringBoot配置actuator,這里大家需要注意可以監(jiān)控SpringBoot?中的?Tomcat?性能數(shù)據(jù),?以日志形式定期輸出監(jiān)控?cái)?shù)據(jù),?只需要配置一個(gè)Bean,需要的朋友可以參考下
    2022-03-03
  • java如何判斷時(shí)間段是否交叉重疊

    java如何判斷時(shí)間段是否交叉重疊

    這篇文章主要介紹了java如何判斷時(shí)間段是否交叉重疊問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • spring security登錄成功后通過Principal獲取名返回空問題

    spring security登錄成功后通過Principal獲取名返回空問題

    這篇文章主要介紹了spring security登錄成功后通過Principal獲取名返回空問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • SpringBoot中的static靜態(tài)資源訪問、參數(shù)配置、代碼自定義訪問規(guī)則詳解

    SpringBoot中的static靜態(tài)資源訪問、參數(shù)配置、代碼自定義訪問規(guī)則詳解

    這篇文章主要介紹了SpringBoot的static靜態(tài)資源訪問、參數(shù)配置、代碼自定義訪問規(guī)則,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • springboot?集成activemq項(xiàng)目配置方法

    springboot?集成activemq項(xiàng)目配置方法

    這篇文章主要介紹了springboot?集成activemq項(xiàng)目配置方法,e-car項(xiàng)目配置通過引入activemq依賴,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • SWT(JFace)體驗(yàn)之FormLayout布局

    SWT(JFace)體驗(yàn)之FormLayout布局

    SWT(JFace)體驗(yàn)之FormLayout布局示例代碼。
    2009-06-06
  • SpringBoot?使用?Sa-Token?完成注解鑒權(quán)功能(權(quán)限校驗(yàn))

    SpringBoot?使用?Sa-Token?完成注解鑒權(quán)功能(權(quán)限校驗(yàn))

    Sa-Token?是一個(gè)輕量級?java?權(quán)限認(rèn)證框架,主要解決登錄認(rèn)證、權(quán)限認(rèn)證、單點(diǎn)登錄、OAuth2、微服務(wù)網(wǎng)關(guān)鑒權(quán)?等一系列權(quán)限相關(guān)問題,這篇文章主要介紹了SpringBoot使用Sa-Token完成注解鑒權(quán)功能,需要的朋友可以參考下
    2023-05-05

最新評論

平遥县| 海口市| 托克逊县| 察隅县| 洞口县| 综艺| 泾源县| 永靖县| 灵丘县| 洛川县| 万安县| 高碑店市| 潮安县| 谢通门县| 牙克石市| 池州市| 泾川县| 夏津县| 特克斯县| 邹平县| 鄢陵县| 同江市| 通化县| 志丹县| 来凤县| 曲靖市| 大足县| 丹棱县| 麻江县| 上蔡县| 长沙县| 郴州市| 南郑县| 普兰县| 定日县| 团风县| 杭锦旗| 宜昌市| 都兰县| 定陶县| 高台县|