免费在线a视频-免费在线观看a视频-免费在线观看大片影视大全-免费在线观看的视频-色播丁香-色播基地

為什么Spring MVC能自動轉(zhuǎn)換json/xml,你研究過它背后的原理嗎?

:2020年03月28日 Java面試那些事兒
分享到:

# 前言SpringMVC是目前主流的Web MVC框架之一。 # 現(xiàn)象本文使用的demo基于maven,是根據(jù)入門blog的例子繼續(xù)寫下去的。我們先來看一看對應(yīng)的現(xiàn)象。我們這里的配置文件 *-dispatcher.xml中的關(guān)鍵配置...

# 前言

SpringMVC是目前主流的Web MVC框架之一。 

# 現(xiàn)象

本文使用的demo基于maven,是根據(jù)入門blog的例子繼續(xù)寫下去的。

我們先來看一看對應(yīng)的現(xiàn)象。我們這里的配置文件 *-dispatcher.xml中的關(guān)鍵配置如下(其他常規(guī)的配置文件不在講解,可參考本文一開始提到的入門blog):

(視圖配置省略)

<mvc:resources location="/static/" mapping="/static/**"/>

<mvc:annotation-driven/>

<context:component-scan base-package="org.format.demo.controller"/>

pom中需要有以下依賴(Spring依賴及其他依賴不顯示):

<dependency>

<groupId>org.codehaus.jackson</groupId>

<artifactId>jackson-core-asl</artifactId>

<version>1.9.13</version>

</dependency>

<dependency>

<groupId>org.codehaus.jackson</groupId>

<artifactId>jackson-mapper-asl</artifactId>

<version>1.9.13</version>

</dependency>

這個依賴是json序列化的依賴。

ok。我們在Controller中添加一個method:

@RequestMapping("/xmlOrJson")

@ResponseBody

public Map<String, Object> xmlOrJson() {

Map<String, Object> map = new HashMap<String, Object>();

map.put("list", employeeService.list());

return map;

}

直接訪問地址:

我們看到,短短幾行配置。使用@ResponseBody注解之后,Controller返回的對象 自動被轉(zhuǎn)換成對應(yīng)的json數(shù)據(jù),在這里不得不感嘆SpringMVC的強大。

我們好像也沒看到具體的配置,唯一看到的就是*-dispatcher.xml中的一句配置:<mvc:annotation-driven/>。其實就是這個配置,導(dǎo)致了java對象自動轉(zhuǎn)換成json對象的現(xiàn)象。

那么spring到底是如何實現(xiàn)java對象到j(luò)son對象的自動轉(zhuǎn)換的呢?為什么轉(zhuǎn)換成了json數(shù)據(jù),如果想轉(zhuǎn)換成xml數(shù)據(jù),那該怎么辦?

# 源碼分析

本文使用的spring版本是4.0.2。 

在講解<mvc:annotation-driven/>這個配置之前,我們先了解下Spring的消息轉(zhuǎn)換機制。@ResponseBody這個注解就是使用消息轉(zhuǎn)換機制,最終通過json的轉(zhuǎn)換器轉(zhuǎn)換成json數(shù)據(jù)的。

HttpMessageConverter接口就是Spring提供的http消息轉(zhuǎn)換接口。有關(guān)這方面的知識大家可以參考"參考資料"中的第二條鏈接,里面講的很清楚。

下面開始分析<mvc:annotation-driven/>這句配置:

這句代碼在spring中的解析類是:

在AnnotationDrivenBeanDefinitionParser源碼的152行parse方法中:

分別實例化了RequestMappingHandlerMapping,ConfigurableWebBindingInitializer,RequestMappingHandlerAdapter等諸多類。

其中RequestMappingHandlerMapping和RequestMappingHandlerAdapter這兩個類比較重要。

RequestMappingHandlerMapping處理請求映射的,處理@RequestMapping跟請求地址之間的關(guān)系。

RequestMappingHandlerAdapter是請求處理的適配器,也就是請求之后處理具體邏輯的執(zhí)行,關(guān)系到哪個類的哪個方法以及轉(zhuǎn)換器等工作,這個類是我們講的重點,其中它的屬性messageConverters是本文要講的重點。

私有方法:getMessageConverters

從代碼中我們可以,RequestMappingHandlerAdapter設(shè)置messageConverters的邏輯:

1.如果<mvc:annotation-driven>節(jié)點有子節(jié)點message-converters,那么它的轉(zhuǎn)換器屬性messageConverters也由這些子節(jié)點組成。

message-converters的子節(jié)點配置如下:

<mvc:annotation-driven>

<mvc:message-converters>

<bean class="org.example.MyHttpMessageConverter"/>

<bean class="org.example.MyOtherHttpMessageConverter"/>

</mvc:message-converters>

</mvc:annotation-driven>

2.message-converters子節(jié)點不存在或它的屬性register-defaults為true的話,加入其他的轉(zhuǎn)換器:ByteArrayHttpMessageConverter、StringHttpMessageConverter、ResourceHttpMessageConverter等。

我們看到這么一段:

這些boolean屬性是哪里來的呢,它們是AnnotationDrivenBeanDefinitionParser的靜態(tài)變量。

 其中ClassUtils中的isPresent方法如下:

看到這里,讀者應(yīng)該明白了為什么本文一開始在pom文件中需要加入對應(yīng)的jackson依賴,為了讓json轉(zhuǎn)換器jackson成為默認(rèn)轉(zhuǎn)換器之一。

<mvc:annotation-driven>的作用讀者也明白了。

下面我們看如何通過消息轉(zhuǎn)換器將java對象進行轉(zhuǎn)換的。

RequestMappingHandlerAdapter在進行handle的時候,會委托給HandlerMethod(具體由子類ServletInvocableHandlerMethod處理)的invokeAndHandle方法進行處理,這個方法又轉(zhuǎn)接給HandlerMethodReturnValueHandlerComposite處理。

HandlerMethodReturnValueHandlerComposite維護了一個HandlerMethodReturnValueHandler列表。

HandlerMethodReturnValueHandler是一個對返回值進行處理的策略接口,這個接口非常重要。然后找到對應(yīng)的HandlerMethodReturnValueHandler對結(jié)果值進行處理。

最終找到RequestResponseBodyMethodProcessor這個Handler(由于使用了@ResponseBody注解)。

RequestResponseBodyMethodProcessor的supportsReturnType方法:

然后使用handleReturnValue方法進行處理:

我們看到,這里使用了轉(zhuǎn)換器。

具體的轉(zhuǎn)換方法:

至于為何是請求頭部的Accept數(shù)據(jù),讀者可以進去debug這個getAcceptableMediaTypes方法看看。我就不羅嗦了~~~

 ok。至此,我們走遍了所有的流程。

現(xiàn)在,回過頭來看。為什么一開始的demo輸出了json數(shù)據(jù)?

我們來分析吧。

由于我們只配置了<mvc:annotation-driven>,因此使用spring默認(rèn)的那些轉(zhuǎn)換器。

很明顯,我們看到了2個xml和1個json轉(zhuǎn)換器。 要看能不能轉(zhuǎn)換,得看HttpMessageConverter接口的public boolean canWrite(Class<?> clazz, MediaType mediaType)方法是否返回true來決定的。

我們先分析SourceHttpMessageConverter:

它的canWrite方法被父類AbstractHttpMessageConverter重寫了。

發(fā)現(xiàn)SUPPORTED_CLASSES中沒有Map類(本文demo返回的是Map類),因此不支持。

下面看Jaxb2RootElementHttpMessageConverter:

這個類直接重寫了canWrite方法。

需要有XmlRootElement注解。很明顯,Map類當(dāng)然沒有。

最終MappingJackson2HttpMessageConverter匹配,進行json轉(zhuǎn)換。(為何匹配,請讀者自行查看源碼)

# 實例講解

 我們分析了轉(zhuǎn)換器的轉(zhuǎn)換過程之后,下面就通過實例來驗證我們的結(jié)論吧。

首先,我們先把xml轉(zhuǎn)換器實現(xiàn)。

之前已經(jīng)分析,默認(rèn)的轉(zhuǎn)換器中是支持xml的。下面我們加上注解試試吧。

由于Map是jdk源碼中的部分,因此我們用Employee來做demo。

因此,Controller加上一個方法:

@RequestMapping("/xmlOrJsonSimple")

@ResponseBody

public Employee xmlOrJsonSimple() {

return employeeService.getById(1);

}

實體中加上@XmlRootElement注解

結(jié)果如下:

我們發(fā)現(xiàn),解析成了xml。

這里為什么解析成xml,而不解析成json呢?

之前分析過,消息轉(zhuǎn)換器是根據(jù)class和mediaType決定的。

我們使用firebug看到:

我們發(fā)現(xiàn)Accept有xml,沒有json。因此解析成xml了。

我們再來驗證,同一地址,HTTP頭部不同Accept。看是否正確。

$.ajax({

url: "${request.contextPath}/employee/xmlOrJsonSimple",

success: function(res) {

console.log(res);

},

headers: {

"Accept": "application/xml"

}

});

$.ajax({

url: "${request.contextPath}/employee/xmlOrJsonSimple",

success: function(res) {

console.log(res);

},

headers: {

"Accept": "application/json"

}

});

驗證成功。

# 關(guān)于配置

如果不想使用<mvc:annotation-driven/>中默認(rèn)的RequestMappingHandlerAdapter的話,我們可以在重新定義這個bean,spring會覆蓋掉默認(rèn)的RequestMappingHandlerAdapter。

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

<property name="messageConverters">

<list>

<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>

<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>

<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>

</list>

</property>

</bean>

或者如果只想換messageConverters的話。

<mvc:annotation-driven>

<mvc:message-converters>

<bean class="org.example.MyHttpMessageConverter"/>

<bean class="org.example.MyOtherHttpMessageConverter"/>

</mvc:message-converters>

</mvc:annotation-driven>

如果還想用其他converters的話。

以上是spring-mvc jar包中的converters。

這里我們使用轉(zhuǎn)換xml的MarshallingHttpMessageConverter。

這個converter里面使用了marshaller進行轉(zhuǎn)換

我們這里使用XStreamMarshaller。

json沒有轉(zhuǎn)換器,返回406.

至于xml格式的問題,大家自行解決吧。這里用的是XStream~。

使用這種方式,pom別忘記了加入xstream的依賴:

<dependency>

<groupId>com.thoughtworks.xstream</groupId>

<artifactId>xstream</artifactId>

<version>1.4.7</version>

</dependency>

# 總結(jié)

 寫了這么多,可能讀者覺得有點羅嗦。畢竟這也是自己的一些心得,希望都能說出來與讀者共享。

剛接觸SpringMVC的時候,發(fā)現(xiàn)這種自動轉(zhuǎn)換機制很牛逼,但是一直沒有研究它的原理,目前,算是了了一個小小心愿吧,SpringMVC還有很多內(nèi)容,以后自己研究其他內(nèi)容的時候還會與大家一起共享的。

文章難免會出現(xiàn)一些錯誤,希望讀者們能指明出來。

# 參考資料

  • http://my.oschina.net/HeliosFly/blog/205343

  • http://my.oschina.net/lichhao/blog/172562

  • http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html

[我要糾錯]
[ 編輯:王振袢 &發(fā)表于江蘇 ]
關(guān)鍵詞: 前言 SpringMVC 目前 流的 框架

來源:本文內(nèi)容搜集或轉(zhuǎn)自各大網(wǎng)絡(luò)平臺,并已注明來源、出處,如果轉(zhuǎn)載侵犯您的版權(quán)或非授權(quán)發(fā)布,請聯(lián)系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內(nèi)容的準(zhǔn)確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負(fù)責(zé),僅作分享之用,文章版權(quán)及插圖屬于原作者。

點個贊
0
踩一腳
0

您在閱讀:為什么Spring MVC能自動轉(zhuǎn)換json/xml,你研究過它背后的原理嗎?

Copyright©2013-2025 ?JSedu114 All Rights Reserved. 江蘇教育信息綜合發(fā)布查詢平臺保留所有權(quán)利

蘇公網(wǎng)安備32010402000125 蘇ICP備14051488號-3技術(shù)支持:南京博盛藍睿網(wǎng)絡(luò)科技有限公司

南京思必達教育科技有限公司版權(quán)所有   百度統(tǒng)計

主站蜘蛛池模板: 久久爰www免费人成 久久在现 | xxxx日本在线播放免费不卡 | 日日碰日日操 | 欧美在线观看一区二区 | 91精品视频免费在线观看 | 女攻高h全肉污文play | 亚洲an天堂an在线观看 | 亚洲日韩精品欧美一区二区一 | 欧美日韩一二三区 | 在线免费观看www视频 | 国产精品国内免费一区二区三区 | 婷婷深爱网| 国产女人视频免费观看 | 欧美性猛交ⅹxxx乱大交按摩 | 免费大香伊蕉在人线国产 | 在线免费观看一级片 | 国产精品欧美在线不卡 | 国产成人短视频 | 91av福利视频 | 国产成人手机在线好好热 | 无遮挡动漫黄漫网站在线观看 | 依欧美视频 | 黄在线 | 欧美亚洲另类色国产综合 | 韩日一区二区三区 | 大杳焦伊人久久综合热 | 国产黄色在线网站 | 337p欧洲亚大胆精品 | 国产午夜三级 | 国产精品欧美一区二区三区不卡 | 国产专区日韩精品欧美色 | 亚洲欧美高清视频 | 色噜噜狠狠狠狠色综合久 | 久久成人免费视频 | 精品久久久久久中文字幕一区 | 午夜影院一级片 | 97色在线观看免费视频 | 亚洲国产最新在线一区二区 | 狠狠欧美 | 欧美色碰碰碰免费观看长视频 | 18女人水真多免费高清毛片 |
最熱文章
最新文章
  • 阿里云上云鉅惠,云產(chǎn)品享最低成本,有需要聯(lián)系,
  • 卡爾蔡司鏡片優(yōu)惠店,鏡片價格低
  • 蘋果原裝手機殼