日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 自定义注解 生成json_用自定义注解实现fastjson序列化的扩展

發(fā)布時間:2025/3/11 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 自定义注解 生成json_用自定义注解实现fastjson序列化的扩展 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這篇文章起源于項(xiàng)目中一個特殊的需求。由于目前的開發(fā)方式是前后端分離的,基本上是通過接口提供各個服務(wù)。

而前兩天前端fe在開發(fā)中遇到了一些問題:他們在處理字符串類型的時間時會出現(xiàn)精度丟失的情況,所以希望后臺是以時間戳的形式返回給前端。而與此同時后臺的設(shè)計(jì)是這個樣子的:所有的時間在數(shù)據(jù)庫中均保存為varchar類型,在序列化的時候也是按String字符串去處理的。

這樣一來就需要一些解決方案:

1. 所有數(shù)據(jù)庫的時間字段都用timestamp替換,這個是最簡單確實(shí)實(shí)現(xiàn)代價(jià)最高的一種方案,由于數(shù)據(jù)庫表太多并且涉及多處的耦合,此方案不可行。

2. 通過fastjson序列化層去轉(zhuǎn)換類型:首先想到的是能不能通過fastjson自己提供的注解方式實(shí)現(xiàn),后調(diào)研之后發(fā)現(xiàn),目前使用的版本并不支持;然后想到可以通過fastjson提供的序列化器重載實(shí)現(xiàn)String類型的攔截并做處理。但是這種方案會把所有String的字段都執(zhí)行這段邏輯,并且還要通過固定的format確定哪些是日期,這里非常影響性能;最后決定添加自定義注解,在需要這種類型轉(zhuǎn)換的字段上加上自定義的@StringToDate注解,然后在序列化執(zhí)行的入口,給所有加了此注解的類提供繼承并實(shí)現(xiàn)擴(kuò)展的序列化器,完成自定義的序列化過程。

下面就詳細(xì)說一下這個過程,一是對fastjson源碼做一個解析和說明,二也是對自己的工作做一個總結(jié)。

1. 如何實(shí)現(xiàn)擴(kuò)展

首先來看一下自定義的注解,很簡單:

關(guān)于這個注解的用法和定義,我就不細(xì)說了,Retention指定了他的作用域,而Target說明該注解用于field字段上。

然后既然是要擴(kuò)展fastjson的功能,我們就來看一下fastjson的入口,首先是WebMvcConfigurerAdapter這個類,我們可以通過繼承和重寫該類的方法實(shí)現(xiàn)MVC的配置,比如攔截器、資源處理器等。我們重寫的方法是configureMessageConverters,這個是用來配置信息轉(zhuǎn)化的converter:

可以看到,我們通過這個方法,調(diào)用了父類,同時加入了fastJson的converter,然后我們來看看FastJsonMessageConverter這個我們自己寫的類:

只是很簡單的通過繼承實(shí)現(xiàn)了自定義config的注入,然后再來看看我們自己寫的這個config:

這里是最關(guān)鍵的地方,SerializeConfig提供一個入口方法getObjectWriter可以用來對傳入的類型進(jìn)行處理,并為相應(yīng)的類型設(shè)置對應(yīng)的Serializer序列化器。這里可以看到,我通過判斷傳入class的注解判斷是不是要處理的類型,如果是需要轉(zhuǎn)換的,就用我們寫的ExtendJavaBeanSerializer去處理他。(同時可以看到,這里我做了緩存處理,每次的class在處理之后都會通過父類的put方法放入緩存,這樣可以大大減少遍歷和判斷的次數(shù),提高處理性能)

那現(xiàn)在就要看看這個ExtendJavaBeanSerializer做了什么:

這里我們繼承了JavaBeanSerializer并重寫了processValue方法。這里要說個點(diǎn):因?yàn)槊總€序列化器都有write方法,所以最開始直觀的想法是重寫這個方法實(shí)現(xiàn)擴(kuò)展,但是由于write方法很長很長(有250多行),作為切入點(diǎn)非常不方便,然后仔細(xì)觀察源碼,發(fā)現(xiàn)其中有這么一句:

propertyValue = this.processValue(serializer, fieldSerializer.fieldContext, object, fieldInfoName,propertyValue);

這句看上去好像就是給我們處理value值的,再點(diǎn)進(jìn)去一看,processValue居然是個protected方法。那正如意!這就是給我們做擴(kuò)展的入口,最后便重寫了這個方法,并在其中實(shí)現(xiàn)了StringToDate的轉(zhuǎn)換邏輯。

2. fastjson源碼思想

其實(shí)呢,到這里應(yīng)該會有一個疑問,fastjson提供的預(yù)設(shè)序列化器有很多很多,看源碼發(fā)現(xiàn)一個包下面滿滿都是。那么我們是如何確定要繼承這個JavaBeanSerializer的呢?這就需要看fastjson的源碼了,看看它究竟是怎么分配和執(zhí)行這個序列化器的:

首先是SerializeConfig這個類:這個類的config中預(yù)設(shè)了大量的類型和序列化器的對應(yīng)關(guān)系,他原有的getObjectWriter入口是這樣的邏輯: 先判斷傳入類是不是config中有的,如果有直接給對應(yīng)的Serializer,如果沒有,又會有一堆特殊類(比如集合,異常,編碼等類)的判斷,而他們也有對應(yīng)的Serializer。

那如果還沒有(比如自己的javabean),在最后會執(zhí)行一個:createJavaBeanSerializer(clazz) 的方法,在這個方法中,默認(rèn)會執(zhí)行createASMSerializer方法,asm查閱資料會發(fā)現(xiàn)是一個老外寫的字節(jié)碼序列化器,是序列化最底層的一個工具,很多開源序列化包都是對這個進(jìn)行封裝實(shí)現(xiàn)的。那我們要繼承JavaBeanSerializer這個類并使用自己的,就說明我們不想讓他執(zhí)行createASMSerializer這個方法,為什么呢?

因?yàn)樵赾reateASMSerializer里面的邏輯是:當(dāng)序列化對象 > 256個時,會創(chuàng)建可繼承的JavaBeanSerializer去處理,如果<256,則不會給他任何序列化器,而是直接通過反射方式在內(nèi)存中(就是生生拼出了一個序列化過程)實(shí)現(xiàn)對這個對象的處理。關(guān)鍵代碼如下:

當(dāng)然,下面還有很長很長的內(nèi)存字節(jié)碼操作的邏輯,我就不貼出了。我想這可能也是fastjson快的一個原因吧。

寫到這里,關(guān)于對fastjson的擴(kuò)展就差不多說完了,其實(shí)fastjson的源碼中其他類中也都有自己獨(dú)特的優(yōu)化方式,有些還是挺有意思的。另外呢,我驚奇地發(fā)現(xiàn),fastjson的作者和durid居然是一個人,這個來自阿里的wenshao還真的厲害啊。作為一個學(xué)習(xí)者,只是希望有朝一日也能寫出這么漂亮的代碼吧,希望自己可以不斷努力!

總結(jié)

以上是生活随笔為你收集整理的java 自定义注解 生成json_用自定义注解实现fastjson序列化的扩展的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。