精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

淺析 SpringMVC 中返回對(duì)象的循環(huán)引用問題

開發(fā) 架構(gòu)
@RestController、@ResponseBody 等注解是我們?cè)趯?Web 應(yīng)用時(shí)打交道最多的注解了,我們經(jīng)常有這樣的需求:返回一個(gè)對(duì)象給前端,SpringMVC 幫助我們序列化成 JSON 對(duì)象。

[[411400]]

本文轉(zhuǎn)載自微信公眾號(hào)「Kirito的技術(shù)分享」,作者kiritomoe 。轉(zhuǎn)載本文請(qǐng)聯(lián)系Kirito的技術(shù)分享公眾號(hào)。

問題發(fā)現(xiàn)

今天這個(gè)話題還是比較輕松的,可能很多朋友也都遇到過這個(gè)問題。

@RestController、@ResponseBody 等注解是我們?cè)趯?Web 應(yīng)用時(shí)打交道最多的注解了,我們經(jīng)常有這樣的需求:返回一個(gè)對(duì)象給前端,SpringMVC 幫助我們序列化成 JSON 對(duì)象。而今天我要分享的話題也不是什么高深的內(nèi)容,那就是返回對(duì)象中存在循環(huán)引用時(shí)問題的探討。

該問題非常簡單容易復(fù)現(xiàn),直接上代碼。

準(zhǔn)備兩個(gè)存在循環(huán)引用的對(duì)象:

  1. @Data 
  2. public class Person { 
  3.     private String name
  4.     private IdCard idCard; 
  5.  
  6. @Data 
  7. public class IdCard { 
  8.     private String id; 
  9.     private Person person; 

在 SpringMVC 的 controller 中直接返回存在循環(huán)引用的對(duì)象:

  1. @RestController 
  2. public class HelloController { 
  3.  
  4.     @RequestMapping("/hello"
  5.     public Person hello() { 
  6.         Person person = new Person(); 
  7.         person.setName("kirito"); 
  8.  
  9.         IdCard idCard = new IdCard(); 
  10.         idCard.setId("xxx19950102xxx"); 
  11.  
  12.         person.setIdCard(idCard); 
  13.         idCard.setPerson(person); 
  14.  
  15.         return person; 
  16.     } 

執(zhí)行 curl localhost:8080/hello 發(fā)現(xiàn),直接報(bào)了一個(gè) StackOverFlowError:

StackOverFlow

問題剖析

不難理解這中間發(fā)生了什么,從堆棧和常識(shí)中都應(yīng)當(dāng)了解到一個(gè)事實(shí),SpringMVC 默認(rèn)使用了 jackson 作為 HttpMessageConverter,這樣當(dāng)我們返回對(duì)象時(shí),會(huì)經(jīng)過 jackson 的 serializer 序列化成 json 串,而另一個(gè)事實(shí)便是 jackson 是無法解析 java 中的循環(huán)引用的,套娃式的解析,最終導(dǎo)致了 StackOverFlowError。

有人會(huì)說,為什么你會(huì)有循環(huán)引用呢?天知道業(yè)務(wù)場(chǎng)景有多奇葩,既然 Java 沒有限制循環(huán)引用的存在,那就肯定會(huì)有某一合理的場(chǎng)景存在該可能性,如果你在線上的一個(gè)接口一直平穩(wěn)運(yùn)行著,知道有一天,碰到了一個(gè)包含循環(huán)引用的對(duì)象,你看著打印出來的 StackOverFlowError 的堆棧,開始懷疑人生,是哪個(gè)小(大)可(S)愛(B)干的這種事!

我們先假設(shè)循環(huán)引用存在的合理性,如何解決該問題呢?最簡單的解法:單向維護(hù)關(guān)聯(lián),參考 Hibernate 中的 OneToMany 關(guān)聯(lián)中單向映射的思想,這需要干掉 IdCard 中的 Person 成員變量。或者,借助于 jackson 提供的注解,指定忽略循環(huán)引用的字段,例如這樣:

  1. @Data 
  2. public class IdCard { 
  3.     private String id; 
  4.     @JsonIgnore 
  5.     private Person person; 

當(dāng)然,我也翻閱了一些資料,嘗試尋求 jackson 更優(yōu)雅的解決方式,例如這兩個(gè)注解:

  1. @JsonManagedReference 
  2. @JsonBackReference 

但在我看來,似乎他們并沒有什么大用場(chǎng)。

當(dāng)然,你如果不嫌棄經(jīng)常出安全漏洞的 fastjson,也可以選擇使用 FastJsonHttpMessageConverter 替換掉 jackson 的默認(rèn)實(shí)現(xiàn),像下面這樣:

  1. @Bean 
  2. public HttpMessageConverters fastJsonHttpMessageConverters() { 
  3.     //1、定義一個(gè)convert轉(zhuǎn)換消息的對(duì)象 
  4.     FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); 
  5.  
  6.     //2、添加fastjson的配置信息 
  7.     FastJsonConfig fastJsonConfig = new FastJsonConfig(); 
  8.  
  9.     SerializerFeature[] serializerFeatures = new SerializerFeature[]{ 
  10.         //    輸出key是包含雙引號(hào) 
  11.         //                SerializerFeature.QuoteFieldNames, 
  12.         //    是否輸出為null的字段,若為null 則顯示該字段 
  13.         //                SerializerFeature.WriteMapNullValue, 
  14.         //    數(shù)值字段如果為null,則輸出為0 
  15.         SerializerFeature.WriteNullNumberAsZero, 
  16.         //     List字段如果為null,輸出為[],而非null 
  17.         SerializerFeature.WriteNullListAsEmpty, 
  18.         //    字符類型字段如果為null,輸出為"",而非null 
  19.         SerializerFeature.WriteNullStringAsEmpty, 
  20.         //    Boolean字段如果為null,輸出為false,而非null 
  21.         SerializerFeature.WriteNullBooleanAsFalse, 
  22.         //    Date的日期轉(zhuǎn)換器 
  23.         SerializerFeature.WriteDateUseDateFormat, 
  24.         //    循環(huán)引用 
  25.         //SerializerFeature.DisableCircularReferenceDetect, 
  26.     }; 
  27.  
  28.     fastJsonConfig.setSerializerFeatures(serializerFeatures); 
  29.     fastJsonConfig.setCharset(Charset.forName("UTF-8")); 
  30.  
  31.     //3、在convert中添加配置信息 
  32.     fastConverter.setFastJsonConfig(fastJsonConfig); 
  33.  
  34.     //4、將convert添加到converters中 
  35.     HttpMessageConverter<?> converter = fastConverter; 
  36.  
  37.     return new HttpMessageConverters(converter); 

你可以自定義一些 json 轉(zhuǎn)換時(shí)的 feature,當(dāng)然我今天主要關(guān)注 SerializerFeature.DisableCircularReferenceDetect 這一屬性,只要不顯示開啟該特性,fastjson 默認(rèn)就能處理循環(huán)引用的問題。

如上配置后,讓我們看看效果:

  1. {"idCard":{"id":"xxx19950102xxx","person":{"$ref":".."}},"name":"kirito"

已經(jīng)正常返回了,fastjson 使用了"$ref":".." 這樣的標(biāo)識(shí),解決了循環(huán)引用的問題,如果繼續(xù)使用 fastjson 反序列化,依舊可以解析成同一對(duì)象,其實(shí)我在之前的文章中已經(jīng)介紹過這一特性了《gson 替換 fastjson 引發(fā)的線上問題分析》。

使用 FastJsonHttpMessageConverter 可以徹底規(guī)避掉循環(huán)引用的問題,這對(duì)于返回類型不固定的場(chǎng)景十分有幫助,而 @JsonIgnore 只能作用于那些固定結(jié)構(gòu)的循環(huán)引用對(duì)象上。

問題思考

值得一提的是,為什么一般標(biāo)準(zhǔn)的 JSON 類庫并沒有如此關(guān)注循環(huán)引用的問題呢?fastjson 看起來反而是個(gè)特例,我覺得主要還是 JSON 這種序列化的格式就是為了通用而存在的,$ref 這樣的契約信息,并沒有被 JSON 的規(guī)范去定義,fastjson 可以確保 $ref 在序列化、反序列化時(shí)能夠正常解析,但如果是跨框架、跨系統(tǒng)、跨語言等場(chǎng)景,這一切都是個(gè)未知數(shù)了。說到底,這還是 Java 語言的循環(huán)引用和 JSON 通用規(guī)范不包含這一概念之間的 gap(可能 JSON 規(guī)范描述了這一特性,但我沒有找到,如有問題,煩請(qǐng)指正)。

我到底應(yīng)該選擇 @JsonIgnore 還是使用 FastJsonHttpMessageConverter 呢?經(jīng)歷了上面的思考,我覺得各位看官應(yīng)該能夠根據(jù)自己的場(chǎng)景選擇合適的方案了。

 

總結(jié)下,如果選擇 FastJsonHttpMessageConverter ,改動(dòng)較大,如果有較多的存量接口,建議做好回歸,以確認(rèn)解決循環(huán)引用問題的同時(shí),別引入了其他不兼容的改動(dòng)。并且,需要基于你的使用場(chǎng)景評(píng)估方案,如果出現(xiàn)了循環(huán)引用,fastjson 會(huì)使用 $ref 來記錄引用信息,請(qǐng)確認(rèn)你的前端或者接口方能夠識(shí)別該信息,因?yàn)檫@可能并不是標(biāo)準(zhǔn)的 JSON 規(guī)范。你也可以選擇 @JsonIgnore 來實(shí)現(xiàn)最小改動(dòng),但也同時(shí)需要注意,如果根據(jù)序列化的結(jié)果再次反序列化,引用信息可不會(huì)自動(dòng)恢復(fù)。

 

責(zé)任編輯:武曉燕 來源: Kirito的技術(shù)分享
相關(guān)推薦

2010-01-25 14:18:46

C++對(duì)象模型

2009-12-29 10:24:51

Linux內(nèi)核循環(huán)鏈表

2009-07-31 18:39:31

C#中foreach引

2009-07-01 09:17:36

對(duì)象比較Java

2011-07-04 09:39:31

項(xiàng)目管理

2009-06-04 09:47:48

MySQL隱藏控件TMPDIR

2021-07-27 22:56:00

JavaScript編程開發(fā)

2023-12-25 09:30:41

Java垃圾回收

2009-12-23 15:08:38

Fedora gcc編

2009-11-03 09:21:26

Visual Stud

2021-10-18 15:50:49

Android強(qiáng)引用軟引用

2021-03-06 14:22:39

池化對(duì)象類庫

2010-01-20 18:24:51

C++CLI

2009-08-06 10:14:15

C#引用類型數(shù)組

2025-01-02 09:48:52

JVMCARD_元素

2011-06-20 15:13:08

Qt 對(duì)象模型

2020-12-17 07:39:30

HashMap死循環(huán)數(shù)據(jù)

2023-03-09 12:30:55

2009-07-10 18:02:05

MyEclipseMySQL

2010-08-27 09:26:32

DHCP server
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

国产高清精品软男同| 久久久久这里只有精品| 中文av一区二区三区| 日韩在线资源| 国产精品1区二区.| 91av在线看| 影音先锋男人在线| 精品国产一区二区三区2021| 午夜av区久久| 一区二区三区不卡在线| 亚洲AV无码一区二区三区性 | 欧美第一视频| 亚洲男人电影天堂| 免费中文日韩| 亚洲第一成年人网站| 日韩不卡视频一区二区| 猫咪在线永久网站| 丁香亚洲综合激情啪啪综合| 国产精品视频99| 精品久久免费视频| 久久香蕉国产| 亚洲欧美日韩天堂| 免费黄色av网址| 欧美成人高清视频在线观看| 欧美性20hd另类| 日韩中文在线字幕| av黄色在线观看| 91免费观看在线| 亚洲一区国产精品| 日韩精品在线观看av| 美女做暖暖视频免费在线观看全部网址91 | 福利91精品一区二区三区| 国产精品久久久久久网站| 国产精品自拍视频一区| 国产韩国精品一区二区三区| 亚洲欧美综合精品久久成人| 国产原创剧情av| 成人短视频软件网站大全app| 在线精品亚洲一区二区不卡| 自慰无码一区二区三区| 888av在线视频| 亚洲乱码日产精品bd| 亚洲欧洲国产日韩精品| 国产高清视频在线观看| 91亚洲精品一区二区乱码| 草莓视频一区| 亚洲第一天堂网| 国产精品一区二区久久精品爱涩| 国产日本欧美视频| 色婷婷久久综合中文久久蜜桃av| 久久不射网站| 日韩av手机在线| 4438国产精品一区二区| 99av国产精品欲麻豆| 久久久亚洲成人| 精品少妇theporn| 欧美日韩亚洲一区在线观看| 欧美精品在线网站| 久久精品黄色片| 中文在线日韩| 欧美大片欧美激情性色a∨久久| 美国一级片在线观看| 91影院成人| 久久精品中文字幕一区| 青青操国产视频| 欧美精品成人| 国外色69视频在线观看| 国产成人免费观看视频 | 一卡二卡三卡在线| 狠狠色综合日日| 91久色国产| 韩国av永久免费| 99麻豆久久久国产精品免费优播| 久草精品电影| 黄色在线视频观看网站| 欧美国产精品一区二区| 伊人色综合影院| 人妖欧美1区| 精品国产成人在线| 搡女人真爽免费午夜网站| 日韩成人在线电影| 日韩女优av电影在线观看| 人妖粗暴刺激videos呻吟| 一道本一区二区三区| 国产亚洲欧美日韩美女| 久久久久久久麻豆| 亚洲国产91| 欧美做爰性生交视频| 99精品欧美一区二区| 久久在线电影| 久久久久久国产免费| 日韩一级在线视频| 国产一区在线看| 精品毛片久久久久久| 最新电影电视剧在线观看免费观看| 亚洲精品中文字幕乱码三区| 精品欧美一区免费观看α√| 黄页免费欧美| 日韩av在线免费看| 国产精品一区二区亚洲| 亚洲国产美女| 国产精品日韩专区| 亚洲欧美另类视频| 欧美国产日本韩| 国产一区二区三区小说| 成人午夜亚洲| 日韩成人黄色av| 卡通动漫亚洲综合| 日本中文在线一区| 激情视频一区二区| av网站在线免费看推荐| 日韩欧美在线一区| 免费观看黄网站| av在线不卡免费观看| 97精品一区二区三区| 国产又粗又猛又黄又爽无遮挡| av不卡一区二区三区| 麻豆视频传媒入口| 精品123区| 日韩成人在线视频网站| 无码黑人精品一区二区| 秋霞成人午夜伦在线观看| 精品国产电影| 日韩影视在线| 7777精品久久久大香线蕉 | 亚洲国产激情av| jizzjizzxxxx| 精品午夜电影| 欧美日韩高清在线观看| 亚洲字幕av一区二区三区四区| 97久久久精品综合88久久| 亚洲国产一二三精品无码| 欧美美女被草| 中文字幕国产精品久久| 国产免费av一区| 成人动漫一区二区在线| 久久久99精品视频| 99综合久久| 色妞久久福利网| 在线播放成人av| 国产日韩综合av| 妺妺窝人体色www在线小说| 中文字幕一区日韩精品| 大胆人体色综合| 国产精品自偷自拍| 国产精品不卡一区| 国产又大又黄又猛| av中文字幕一区二区| 国产精品 欧美在线| 亚洲av毛片成人精品| 黄色成人av在线| 欧美肉大捧一进一出免费视频| 亚洲性感美女99在线| 国产激情一区二区三区在线观看| 日本乱理伦在线| 精品av久久707| 日本三级2019| 97久久超碰国产精品电影| 日韩人妻无码精品久久久不卡| 日本免费精品| 欧美—级a级欧美特级ar全黄| www.香蕉视频| 午夜精品一区二区三区三上悠亚| www.日本高清| 天堂一区二区在线| 新呦u视频一区二区| 欧美一级做a| 久久久精品美女| 亚洲av无码一区二区三区dv | 欧美精品久久96人妻无码| 免费观看亚洲天堂| 午夜精品蜜臀一区二区三区免费| 天天干天天干天天干| 大桥未久av一区二区三区| 性久久久久久久久久 | 欧美一级小视频| 综合国产在线| 精品999在线观看| 日韩精品麻豆| 超碰91人人草人人干| 日本精品久久久久| 在线影院国内精品| 欧美人妻精品一区二区三区| aaa欧美日韩| 四季av一区二区| 这里只有精品在线| 久久精品第九区免费观看| 超薄肉色丝袜脚交一区二区| 九九九久久久久久| 欧美性孕妇孕交| 91精品国产综合久久久蜜臀图片| 久久精品视频国产| 国产女人水真多18毛片18精品视频| 五月天丁香花婷婷| 国产精品视频| 性欧美18一19内谢| 日韩欧美国产大片| 国产在线一区二区三区| 黄视频免费在线看| www亚洲欧美| 亚洲三区在线播放| 欧美一区二区三区在| 成人毛片18女人毛片| 国产精品网站一区| av黄色一级片| 久久99精品久久久| 亚洲国产精品久久久久婷蜜芽| 国产韩国精品一区二区三区| 久久综合中文色婷婷| 国产精品1区在线| 国产精品高清免费在线观看| 欧美女同一区| 久久精品视频亚洲| 激情视频在线观看免费| 精品久久久网站| 国产视频手机在线| 91福利在线播放| 激情五月色婷婷| 亚洲精品免费在线播放| 亚洲一级片在线播放| 99久久99久久免费精品蜜臀| 天堂av.com| 免费成人美女在线观看| 成年人观看网站| 一区在线观看| 400部精品国偷自产在线观看| 欧美三级三级| 欧美激情第一页在线观看| 亚洲性视频在线| 亚洲一区二区三区乱码aⅴ蜜桃女| 人人鲁人人莫人人爱精品| 久久久久久久久中文字幕| 黄网址在线观看| 中文字幕在线国产精品| 国产一级网站视频在线| 亚洲女成人图区| 天堂av中文字幕| 亚洲成人黄色在线观看| av观看在线免费| 欧美一级日韩一级| 国产熟女一区二区三区五月婷| 欧美日韩一卡二卡三卡| 国产精品第6页| 在线看国产日韩| 日韩精品一区二区亚洲av观看| 欧美性极品少妇精品网站| 国产精品黄色网| 调教+趴+乳夹+国产+精品| 国产在线视频二区| 亚洲一二三专区| 国产91av视频| 黑人精品xxx一区一二区| www..com国产| 精品久久久久久久久国产字幕| 日韩手机在线观看| 精品毛片三在线观看| 欧美特黄aaaaaa| 欧美视频在线视频| 秋霞av一区二区三区| 在线影视一区二区三区| 一本一道人人妻人人妻αv| 欧美另类videos死尸| 国产精品无码在线播放| 欧美一区二区三区在线观看| 亚洲精品911| 亚洲精品美女在线| 国产高清在线| 久久久999精品| 暖暖在线中文免费日本| 91tv亚洲精品香蕉国产一区7ujn| xx欧美视频| 国产精品亚发布| 久久一级大片| 国产一区喷水| 国产尤物久久久| 一区二区在线观| 欧美网站在线| 精品人妻一区二区三区四区在线| 日本午夜精品一区二区三区电影 | 亚洲午夜精品久久| 亚洲欧美亚洲| 国产在线青青草| 欧美bbbbb| 一级黄色大片免费看| 2020国产精品自拍| 精品在线观看一区| 亚洲高清一区二区三区| 伊人久久久久久久久久久久| 制服.丝袜.亚洲.中文.综合| 日韩中文字幕免费观看| 亚洲人成电影在线播放| 亚洲综合影视| 国产mv久久久| 一本一道久久a久久| 欧美日韩一区二区视频在线观看| 91视频综合| 黄www在线观看| 国内精品自线一区二区三区视频| 一级特级黄色片| 中文字幕一区二区三区在线观看| 国产系列精品av| 欧美日韩精品一区视频| 午夜影院免费体验区| 久久久久999| 韩国久久久久久| 99久久自偷自偷国产精品不卡| 精品日韩毛片| 九九爱精品视频| 国产在线精品一区二区三区不卡| 在线观看国产网站| 亚洲精品午夜久久久| 久久久久女人精品毛片九一| 欧美美女bb生活片| 九色在线视频| 久久乐国产精品| 9999精品| 亚洲精品久久久久久一区二区| 国产精品嫩草99av在线| 久久久久亚洲av无码麻豆| 国产欧美一区二区三区在线看蜜臀 | 久久aimee| 免费日韩在线观看| 麻豆精品国产91久久久久久| 日韩在线免费观看av| 偷拍亚洲欧洲综合| 亚洲成熟女性毛茸茸| 精品激情国产视频| 三上悠亚激情av一区二区三区 | 中文字幕亚洲欧洲| 久久久久国产精品麻豆ai换脸| 免费无码毛片一区二区app| 欧美日韩国产成人在线免费| 国产女人在线视频| 国产aaa精品| 伊人成综合网yiren22| 国内自拍在线观看| 成人av资源在线观看| 欧美成人综合色| 欧美一区二区免费观在线| 一区二区三区视频网站| 国产精品丝袜一区二区三区| 欧美日韩水蜜桃| 爱情岛论坛vip永久入口| 国产亚洲一二三区| 香蕉污视频在线观看| 亚洲视频在线看| 国产精品扒开腿做爽爽爽视频软件| 免费中文日韩| 久久一二三区| 永久免费成人代码| 在线观看中文字幕不卡| 免费在线国产| 国产精品99久久久久久久久久久久| 国产麻豆一区二区三区精品视频| 九热视频在线观看| 国产精品欧美一级免费| 一级特黄色大片| 久热精品视频在线免费观看 | 91精品国产麻豆| 黄网站在线免费| 成人av片网址| 99亚洲一区二区| 魔女鞋交玉足榨精调教| 色综合久久久久久久久久久| 懂色av中文在线| 成人在线视频网| 国内自拍一区| 黄色a一级视频| 色婷婷激情一区二区三区| 北岛玲日韩精品一区二区三区| 国产精品一区专区欧美日韩| 亚洲国产精品日韩专区av有中文| 亚洲成人激情小说| 亚洲成av人影院| 国产区在线视频| 91欧美激情另类亚洲| 亚洲小说欧美另类社区| www.av欧美| 7777女厕盗摄久久久| heyzo在线| 丝袜足脚交91精品| 国产乱码精品一区二区三区av| 日产精品久久久久| 在线观看国产精品淫| 日韩精品成人在线观看| 成年人视频观看| 中文字幕欧美一| 天天爽夜夜爽夜夜爽| 国产自产女人91一区在线观看| 欧美成人国产| 无码国产69精品久久久久同性| 91精品麻豆日日躁夜夜躁| 人人草在线视频| 自拍偷拍亚洲色图欧美| 不卡的看片网站| 一级成人免费视频| 97色伦亚洲国产| 在线观看国产精品入口| 91网站免费视频| 亚洲第一免费播放区|