国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于SpringBoot結(jié)果集序列化過濾插件的研究與實(shí)現(xiàn)

2020-10-20 03:23:49王春波葛雷文雪巍
商情 2020年41期
關(guān)鍵詞:堆棧序列化

王春波 葛雷 文雪巍

【摘要】SpringBoot是由Pivotal團(tuán)隊(duì)在2013年開始研發(fā)、2014年4月發(fā)布第一個(gè)版本的全新開源的輕量級(jí)框架。它基于Spring4.0設(shè)計(jì),不僅繼承了Spring框架原有的優(yōu)秀特性,而且還通過簡化配置來進(jìn)一步簡化了Spring應(yīng)用的整個(gè)搭建和開發(fā)過程。該框架使用內(nèi)置的注解與Jackson插件可方便的將結(jié)果集序化成適合于移動(dòng)互聯(lián)網(wǎng)廠商作為業(yè)務(wù)接口的JSON格式字符串。由于框架的高度集成使得結(jié)果集序列化成JSON字符串時(shí)過于規(guī)則化,不能適用于較為復(fù)雜的業(yè)務(wù)場景,且對(duì)于復(fù)雜的結(jié)果集還會(huì)出現(xiàn)堆棧溢出錯(cuò)誤,筆者分析了SpringBoot消息序列化過程,結(jié)合業(yè)務(wù)場景,給出了如何靈活定義結(jié)果集序列化規(guī)則,如何避免堆棧溢出錯(cuò)誤的設(shè)計(jì)與實(shí)現(xiàn)方法,從而為使用SpringBoot框架作為開發(fā)技術(shù)棧的項(xiàng)目組提供了借鑒與參考。

【關(guān)鍵詞】SpringBoot? Jackson? 堆棧? JSON? 序列化

一、引言

Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來簡化新Spring應(yīng)用的初始搭建以及開發(fā)過程。該框架使用了特定的方式來進(jìn)行配置,從而使開發(fā)人員不再需要定義樣板化的配置。通過這種方式,Spring Boot致力于在蓬勃發(fā)展的快速應(yīng)用開發(fā)領(lǐng)域成為領(lǐng)導(dǎo)者。

SpringBoot框架中有兩個(gè)非常重要的策略:開箱即用和約定優(yōu)于配置。開箱即用,是指在開發(fā)過程中,通過在MAVEN項(xiàng)目的pom文件中添加相關(guān)依賴包,然后使用對(duì)應(yīng)注解來代替繁瑣的XML配置文件以管理對(duì)象的生命周期。這個(gè)特點(diǎn)使得開發(fā)人員擺脫了復(fù)雜的配置工作以及依賴的管理工作,更加專注于業(yè)務(wù)邏輯。約定優(yōu)于配置,是一種由SpringBoot本身來配置目標(biāo)結(jié)構(gòu),由開發(fā)者在結(jié)構(gòu)中添加信息的軟件設(shè)計(jì)范式。這一策略減少了開發(fā)人員需要做出決定的數(shù)量,同時(shí)減少了大量的XML配置,并且可以將代碼編譯、測試和打包等工作自動(dòng)化,但也降低了部分靈活性,增加了缺陷定位的復(fù)雜性。

對(duì)于復(fù)雜的項(xiàng)目需求,SpringBoot缺少靈活性的結(jié)果集轉(zhuǎn)換方式,不但不能降低開發(fā)人員勞動(dòng)強(qiáng)度和復(fù)雜度,相反極大的增加了開發(fā)人員的工作量以及出現(xiàn)去缺陷的可能。因此,需要找到一個(gè)確實(shí)有效方法允許開發(fā)人員靈活配置結(jié)果集序列化規(guī)則,但同時(shí)又不能破壞或改變SpringBoot框架原有的優(yōu)勢(shì)。

二、SpringBoot結(jié)果集序列化的現(xiàn)狀與問題

SpringBoot默認(rèn)使用Jackson插件進(jìn)行結(jié)果集序列化。SpringBoot允許開發(fā)者使用其他插件例如Fastjson替換默認(rèn)的Jackson進(jìn)行結(jié)果集序列化,但無論使用哪種插件都面臨著序列化規(guī)則僵化、不靈活的弊端。試想當(dāng)相同的視圖對(duì)象應(yīng)用于不同的請(qǐng)求接口時(shí),就會(huì)出現(xiàn)需要的請(qǐng)求字段不一樣場景,例如以下部門定義實(shí)體:

public class SysDepart {

private String departAddr; //部門地址

private String departPhone; //部門電話

private Integer departLevel; //部門級(jí)別

private String departName; //部門名稱

private String departExplain; //部門說明

private String departType; //部門類型

private SysSchool school; //歸屬學(xué)校

private SysDepart parentDepart ; //父級(jí)部

private List staff; //歸屬該部門的員工列表

}

針對(duì)獲取部門基本信息的接口,僅需要返回departAddr、departLevel、departName、departExplain、departType這個(gè)五個(gè)屬性字段即可;針對(duì)獲取部門員工列表的接口,僅需返回List staff 這個(gè)屬性字段即可;

對(duì)于這類問題通常有以下4中解決辦法:

(1)返回全部屬性字段:即由接口發(fā)起方進(jìn)行二次判斷,這種解決辦法不僅增加了開發(fā)人員的工作量,也給系統(tǒng)帶來了額外開銷。特別的,如果視圖對(duì)象存在雙向關(guān)聯(lián)關(guān)系,即SysDepart擁有屬性字段SysSchool school,同時(shí)SysSchool擁有屬性字段List depart;兩個(gè)實(shí)體構(gòu)成雙向一對(duì)多關(guān)系時(shí),用Jackson或Fastjson等插件進(jìn)行結(jié)果序列化時(shí)均會(huì)出現(xiàn)堆棧溢出錯(cuò)誤。

(2)結(jié)果集二次處理:適當(dāng)增加注解,對(duì)結(jié)果集進(jìn)行二次處理。該方法雖能夠避免開發(fā)人員進(jìn)行多余的判斷,但卻不能避免首次結(jié)果集序列化JSON時(shí)發(fā)起的不需要的關(guān)聯(lián)查詢,以及避免序列化兩個(gè)構(gòu)成雙向一對(duì)多關(guān)系實(shí)體時(shí)出現(xiàn)的堆棧溢出錯(cuò)誤。

(3)Jackson提供@JsonFilter 注解實(shí)現(xiàn)結(jié)果集的動(dòng)態(tài)過濾,但該注解使用麻煩,需要一個(gè)對(duì)象寫多個(gè)子類以區(qū)分不同的結(jié)果集,對(duì)于更復(fù)雜關(guān)聯(lián)查詢則顯得捉襟見肘。

(4)無論是Jackson還是FastJson都提供了簡單過濾器,但這類過濾器僅能進(jìn)行全局配置,無法做到個(gè)性化輸出。

綜上所述,無論是SpringBoot官方還是插件提供商均未曾為該類問題提供方便有效的解決辦法。筆者充分分析SpringBoot結(jié)果集序列化過程,通過擴(kuò)展接口、自定義解析規(guī)則、增加必要注解,利用AOP編程思想編碼實(shí)現(xiàn)了解決該類問題的插件,插件命名為Power-filter。Power-filter可以根據(jù)不同的業(yè)務(wù)場景配置返回不同的結(jié)果集,不僅能夠有效避免雙向關(guān)聯(lián)實(shí)體bean因循環(huán)查詢導(dǎo)致的堆棧溢出問題,也能減少非必要查詢,降低開發(fā)人員的編碼復(fù)雜度的同時(shí)也提高系統(tǒng)的查詢效率。

三、Power-filter的設(shè)計(jì)與實(shí)現(xiàn)

(一)SpringBoot 消息序列化原理

SpringBoot使用消息轉(zhuǎn)換器對(duì)結(jié)果集進(jìn)行序列化,原理圖如圖1:

從圖2可知,客戶端發(fā)送消息時(shí),消息轉(zhuǎn)換器的作用是將對(duì)象序列化為某一格式報(bào)文,然后將報(bào)文發(fā)送另一端;接收消息時(shí),消息轉(zhuǎn)換器作用是將某一格式報(bào)文轉(zhuǎn)換為對(duì)象。

SpringBoot框架內(nèi)置了很多HTTP消息轉(zhuǎn)換器,不同消息類型轉(zhuǎn)換器處理不同Content-type類型數(shù)據(jù)。如MappingJackson2HttpMessageConverter處理請(qǐng)求類型為application/json類型數(shù)據(jù), StringHttpMessageConverter 處理類型為為 text/

html類型數(shù)據(jù)等。在框架內(nèi)部會(huì)根據(jù)不同請(qǐng)求類型值選擇不同類型轉(zhuǎn)換器進(jìn)行消息轉(zhuǎn)換。目前,結(jié)果集的序列化過程就是通過默認(rèn)名為MappingJackson2HttpMessageConverter的轉(zhuǎn)換器來實(shí)現(xiàn)的。

SpringBoot框架提供了HTTP消息轉(zhuǎn)換器的處理接口,允許開發(fā)者自定義消息序列化規(guī)則,因此可通過實(shí)現(xiàn)消息轉(zhuǎn)換器處理接口,用于替換原有處理application/json類型數(shù)據(jù)的轉(zhuǎn)換器來達(dá)到動(dòng)態(tài)過濾屬性字段的需求。

(二)Power-filter設(shè)計(jì)思路

Power-filter的設(shè)計(jì)目的是為了在原有的框架上擴(kuò)展功能,適應(yīng)多變的接口需求。通過深入分析 SpringBoot 消息序列化原理,結(jié)合需求,筆者得出如圖2的設(shè)計(jì)思路。

圖2中標(biāo)識(shí)①②③的區(qū)域是Power-filter插件實(shí)現(xiàn)的關(guān)鍵點(diǎn):①允許開發(fā)者根據(jù)不同業(yè)務(wù)接口需求靈活設(shè)置序列化規(guī)則。②請(qǐng)求發(fā)起時(shí),框架能夠獲取到針對(duì)該請(qǐng)求設(shè)置的過濾規(guī)則,并緩存它。③SpringBoot調(diào)用自定義的消息轉(zhuǎn)換器,獲取相應(yīng)規(guī)則,解析并應(yīng)用規(guī)則進(jìn)行消息序列化。

(三)Power-filter實(shí)現(xiàn)方法

針對(duì)圖2的設(shè)計(jì)思路中提到的三個(gè)關(guān)鍵點(diǎn),實(shí)現(xiàn)方式如下:

(1)對(duì)于①,筆者使用注解的方式進(jìn)行實(shí)現(xiàn)。Java 注解又稱 Java 標(biāo)注,它允許Java 語言中的類、方法、變量、參數(shù)和包等都可以被標(biāo)注。Power-filter新定義的注解如下:

注解1:PowerJsonFilter

@Retention(RUNTIME)

@Target(value = {ElementType.METHOD})

@Repeatable(value=PowerJsonFilters.class)

public @interface PowerJsonFilter {

Class<?> clazz();

String[] include() default {};// include為對(duì)象需要包含的字段

}

注解2:PowerJsonFilters

@Retention(RUNTIME)

@Target({METHOD })

public @interface PowerJsonFilters {

PowerJsonFilter[] value();

}

從代碼中可以看出,兩個(gè)注解只能使用在方法上,注解2是注解1的數(shù)組形態(tài),可支持多規(guī)則設(shè)置。注解1接收兩個(gè)參數(shù):

clazz:用于指示哪些實(shí)體bean需要消息序列化。如 clazz = SysDepart.class

include:為字符串?dāng)?shù)組類型,用于指示需要消息序列化的實(shí)體bean中哪些屬性可以被序列化,它的格式如下:include = {"字段1","字段2","字段m","字段x:{字段x-1, 字段x-2:{ 字段x-2-1,[字段y:{…}]}}","字段n"}。舉例說明該格式的含義,對(duì)于注解:@PowerJsonFilters({@PowerJsonFilter(clazz = SysDepart.class,include= {"departId","departName" ,"parentDepart:{departName,school:

{schoolName}}"}))。它的含義是:對(duì)于SysDepart實(shí)體bean,需要對(duì)其屬性"departId","departName","parentDepart"進(jìn)行序列化,特別的對(duì)于parentDepart屬性,其所屬類型不是簡單字符串、整形等常用數(shù)據(jù)類型,而是用戶自定義的實(shí)體,parentDepart:{departName,school:{schoolName}}意味著僅需要序列化parentDepart所屬實(shí)體的"departName","school"屬性。對(duì)于school屬性也做同樣的解析。該規(guī)則支持多重嵌套,只要開發(fā)人員設(shè)置合理,即可避免實(shí)體bean的雙向關(guān)聯(lián)查詢導(dǎo)致的堆棧溢出錯(cuò)誤。

(2)對(duì)于②,使用AOP編程思想,定義新的切入點(diǎn),實(shí)現(xiàn)流程圖如圖3:

(3)對(duì)于③,需要遵守SpringBoot框架的消息轉(zhuǎn)換器的接口規(guī)范進(jìn)行實(shí)現(xiàn),實(shí)現(xiàn)流程如圖4:

四、Power-filter應(yīng)用與對(duì)比測試

(一)Power-filter安裝與應(yīng)用

Power-filter的設(shè)計(jì)初衷是解決SpringBoot對(duì)結(jié)果集進(jìn)行序列化時(shí)遇到諸多不便問題,因此Power-filter僅是SpringBoot的有益補(bǔ)充,它的安裝使用依賴于SpringBoot框架。Power-filter的安裝使用步驟為:

(1)在SpringBoot啟動(dòng)方法上增加注解掃描范圍,例如:@SpringBootApplication(scanBasePackages = {"xxx.xxx.xxx","com.hanb.filterJson"})

(2)刪除原有消息轉(zhuǎn)換器,增加自定義的消息轉(zhuǎn)換器,代碼如下:

public void configureMessageConverters(List> converters) {

for (int i = converters.size() - 1; i >= 0; i--) {

//找到并刪除默認(rèn)的消息轉(zhuǎn)換器

}

//聲明自定義消息轉(zhuǎn)換器并加入消息轉(zhuǎn)換器轉(zhuǎn)換鏈

PowerHttpMessageConverter myConverter=new PowerHttpMessageConverter();

converters.add(myConverter);

}

(3)在需要定義序列化規(guī)則的方法上增加注解,代碼示例如下:

@RestController

public class XxAction {

@PowerJsonFilters({@PowerJsonFilter(clazz = SysDepart.class,include =? {"departId","school","parentDepart:{departName,school:{schoolName}}"}),

@PowerJsonFilter(clazz = School.class,include = {"schoolAddr"})})

public Object queryDepart(參數(shù)列表)? throws Exception{

//業(yè)務(wù)邏輯代碼

}? }

通過(1)、(2)的安裝,(3)的應(yīng)用,程序運(yùn)行后即可得出規(guī)則設(shè)定的結(jié)果,如下示例:

[{"departId":1,"school":{"schoolAddr":"學(xué)院路"}},{"departId":2,"parentDepart":{"departName":"1級(jí)部門","school":{"schoolName":"財(cái)經(jīng)"}},"school":{"schoolName":"財(cái)經(jīng)"}}]

(二)SpringBoot使用Power-filter插件序列化效率前后對(duì)比

Power-filter能夠通過設(shè)置過濾規(guī)則靈活對(duì)結(jié)果集進(jìn)行過濾,為了對(duì)比應(yīng)用插件前后的效率,筆者在同一軟硬件環(huán)境下分別做了單表查詢結(jié)果集序列化,多表關(guān)聯(lián)查詢結(jié)果集序列化對(duì)比測試。

(1)單表查詢100條記錄序列化對(duì)比如圖5:

(2)多表關(guān)聯(lián)查詢100條記錄序列化對(duì)比如圖6。

通過對(duì)比測試可發(fā)現(xiàn),對(duì)于單表查詢,兩者對(duì)查詢結(jié)果的序列化耗時(shí)相差并不大,對(duì)于多表關(guān)聯(lián)查詢,框架由于應(yīng)用了過濾規(guī)則避免了無用屬性的關(guān)聯(lián)查詢與序列化,其效率大大提高。

五、總結(jié)

Power-filter是依賴于SpringBoot框架的插件,該插件使用AOP編程思想進(jìn)行編寫,主要做了以下3點(diǎn)工作:

(1)新增注解,用于對(duì)查詢結(jié)果集序列化規(guī)則進(jìn)行配置。

(2)新增過濾規(guī)則,使用堆數(shù)據(jù)結(jié)構(gòu)完成對(duì)實(shí)體bean的多層嵌套比對(duì)。

(3)實(shí)現(xiàn)自定義的消息轉(zhuǎn)換器,替換SpringBoot原生插件,完成結(jié)果集的序列化。

通過對(duì)比測試發(fā)現(xiàn),使用了Power-filter插件的SpringBoot有以下4點(diǎn)優(yōu)勢(shì):

(1)配置規(guī)則簡單易懂,學(xué)習(xí)成本極低。

(2)對(duì)結(jié)果集序列化按規(guī)則進(jìn)行配置,使得業(yè)務(wù)接口更加靈活,降低開發(fā)者的大量重復(fù)性工作。

(3)通過規(guī)則配置,可有效避免無用屬性字段的關(guān)聯(lián)查詢,節(jié)約了系統(tǒng)開銷。

(4)通過規(guī)則配置,可有效避免雙向關(guān)聯(lián)實(shí)體bean引起的循環(huán)查詢,從而導(dǎo)致的堆棧溢出錯(cuò)誤。

Power-filter作為SpringBoot的非原生插件,雖然有著自身的優(yōu)點(diǎn),但也存在著不足:

(1)需要做額外配置,插件方可生效。

(2)過濾規(guī)則暫不支持通配符配置,規(guī)則書寫略顯麻煩。

(3)規(guī)則配置方式單一,目前僅支持包含設(shè)置,不支持排除設(shè)置。

對(duì)于不足中的(2)和(3),筆者將繼續(xù)完善該插件,爭取早日彌補(bǔ)其不足。

總之,Power-filter作為SpringBoot的有益補(bǔ)充,雖然有些許不足,但仍能夠?yàn)槭褂肧pringBoot框架作為開發(fā)技術(shù)棧的項(xiàng)目組提供借鑒與參考,為其快速完成接口開發(fā)提供有效的解決方案。

參考文獻(xiàn):

[1]小馬哥. Spring Boot編程思想(核心篇)[M].北京:電子工業(yè)出版社,2019:155-187.

[2][美] Bruce Eckel.Think In Java)[M].北京:機(jī)械工業(yè)出版社,2007:162-199.

[3]王曉東,計(jì)算機(jī)算法設(shè)計(jì)與分析(第5版))[M],北京:電子工業(yè)出版社,2018:202-351.

作者簡介: 王春波(1978-),男,漢族,黑龍江海倫市人,碩士,信息系統(tǒng)項(xiàng)目高級(jí)管理師,研究方向:軟件工程、大數(shù)據(jù)理論、神經(jīng)網(wǎng)路算法;葛雷(1973-),男,漢族,黑龍江哈爾濱人,碩士,教授,研究方向:軟件工程、教育理論;文雪?。?979-),女,漢族,黑龍江哈爾濱人,碩士,教授,主研究方向:軟件工程、人工智能。

猜你喜歡
堆棧序列化
如何建構(gòu)序列化閱讀教學(xué)
甘肅教育(2020年14期)2020-09-11 07:58:36
嵌入式軟件堆棧溢出的動(dòng)態(tài)檢測方案設(shè)計(jì)*
基于堆棧自編碼降維的武器裝備體系效能預(yù)測
Java 反序列化漏洞研究
作文訓(xùn)練微格化、序列化初探
Java序列化技術(shù)的探討
一種用于分析MCS-51目標(biāo)碼堆棧深度的方法
堆棧技術(shù)及其在程序設(shè)計(jì)中的靈活運(yùn)用
和静县| 峨眉山市| 晋州市| 乐亭县| 隆回县| 黑龙江省| 东乡族自治县| 江北区| 霍州市| 文昌市| 新田县| 那坡县| 巴塘县| 墨竹工卡县| 虹口区| 无为县| 山东省| 翼城县| 伊通| 仁布县| 丽江市| 临清市| 友谊县| 汽车| 营山县| 瑞金市| 和龙市| 平罗县| 九江市| 金塔县| 四平市| 北海市| 祁连县| 荃湾区| 绍兴县| 广元市| 若尔盖县| 邯郸县| 新巴尔虎左旗| 长寿区| 宾川县|