溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何用Java反射提高開發(fā)效率的框架

發(fā)布時間:2021-12-22 11:29:01 來源:億速云 閱讀:96 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“如何用Java反射提高開發(fā)效率的框架”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

基于spring的aop,定義一個注解做為切點,注釋在service層的分頁查詢方法上,聲明方法的返回結果POJO對象的哪個字段需要應用默認值規(guī)則。

通過aop在方法執(zhí)行完成之后,給返回結果應用配置的默認值規(guī)則,再返回給前端,如下圖所示。


 

如何用Java反射提高開發(fā)效率的框架


 

如果一次查詢返回含有20個元素的數(shù)組List<R>,要對每個元素R都反射查找一次Field,判斷該Field的值,如果為空則賦值為默認值,那就是重復做反射獲取Field,亂用反射,延長接口的響應時間。


 

對于默認值規(guī)則應用這個例子,我們可以有很好的做法,拿到R類中的name字段,即Field,只需要反射一次。就是在應用啟動時,執(zhí)行包掃描獲取到R的Class對象,執(zhí)行反射獲取R類型中所有的Field,然后使用Map<Class,Map<字段名,F(xiàn)ield>>緩存在內(nèi)存中,這樣用到的時候就能很快拿到。雖然會消耗點內(nèi)存,但這是可以忽略的,因為整個系統(tǒng)應用到默認值規(guī)則的類就沒幾個。


 

我認為我設計的這套默認值規(guī)則是最優(yōu)的方案。

1、使用aop實現(xiàn)代碼的解耦,默認值規(guī)則的應用邏輯不侵入業(yè)務代碼,隨時可對這個功能進行插拔。


 

2、同時,利用反射可以實現(xiàn)添加默認值規(guī)則不需要改動任何代碼,隨時添加隨時用,隨時修改隨時生效。


 

3、再者,由于默認值規(guī)則存在的很少改動這個特性,使用內(nèi)存緩存,有效減少數(shù)據(jù)庫的查詢次數(shù),也是對性能的一個提升。


 

…………… 利用反射提高工作效率  …………  


 

業(yè)務場景簡介  


 

今天,我繼續(xù)分享另一種反射的使用場景,包括如何設計實現(xiàn)。以此,回答本篇文章開頭的問題,怎樣才算用到刀刃上。


 

先了解點簡單的業(yè)務場景,這段內(nèi)容主要介紹使用場景,看不懂沒關系,大概過一遍就行。


本次優(yōu)化的是一個定時任務服務,它要做的就是調(diào)用很多第三方的接口拉取數(shù)據(jù),并轉為平臺統(tǒng)一結構的數(shù)據(jù),如將A、B、C…轉為P,存入到數(shù)據(jù)庫中。


假如我有一個產(chǎn)品,需要做推廣,那我就是上游廣告主,而我想投放到百度搜索、微信朋友圈展示,那么百度和微信就是下游渠道。但中間可能經(jīng)過幾層渠道,而中間的每一個渠道對于下游來說都是一個廣告主,也都可以稱為網(wǎng)盟平臺,大家可能會對百度網(wǎng)盟廣告平臺有所耳聞。



如何用Java反射提高開發(fā)效率的框架


那么作為一個網(wǎng)盟平臺,需要整合上游的Offer,批給下游去展示。整合上游的 Offer就是調(diào)用每個上游提供的api。但每個上游所返回的json數(shù)據(jù)都不一樣,字段名稱也不一樣。那就需要為每個api實現(xiàn)一個解析映射的方法。這就是重復勞動。如何減少這種重復勞動,就是提高工作效率。


簡單一句話,要做什么


與Mybatis實現(xiàn)的將查詢結果映射成pojo對象的過程相似。如果還覺得這段內(nèi)容抽象,那就直接跳過吧,我改了好幾次,發(fā)現(xiàn)都好難表述清楚啊。


解析映射,就是將json數(shù)據(jù)解析后得到的java對象Response,之后,再獲取到Response中存放廣告信息數(shù)組(List)的字段的值,再遍歷該List,將每個元素由類型A轉為平臺統(tǒng)一的類型對象B,這個過程就是A to B,比如。


class A{

        String a_name;

}


Class B{

       String name;

}


實現(xiàn) A==>to ==> B 就是:

A a;

B b;

b.setName(a.getA_name());


很顯然,直接使用反射copy字段的值是沒有用的,一是字段名不同,二是可能字段的類型也不同,三是還可能是下面這樣情況。


class A{

       C c;

      public static class C{

              String c_name;

       }

}


 

class B{

       String name;

}


實現(xiàn) A==>  to ==> B 就是:

A a;

B b;

b.setName(a.getC().get C_name());


如何實現(xiàn)自動映射


如果可以添加一個注解,在注解中聲明映射規(guī)則,比如其中一條:class A中的name字段對應class B中的pkgName字段。


如果能根據(jù)注解聲明的一個個映射規(guī)則,完成自動映射,就可以不用每次都寫這些重復代碼了。是的,我要實現(xiàn)的就是這樣一個功能。


P.S:最后我還加入了插件功能,滿足一些需要做特殊處理的需求。


類結構樹的定義


知道我為啥叫它結構樹嗎?二叉樹不是二叉樹,n差數(shù)不是n叉樹,我不懂怎么叫,難道這是我自己發(fā)明的?哈哈。


以一個例子來講,不那么抽象。如圖,實現(xiàn)自動從TestResponse對象中,拿到List<RowsetBean> rowset的值。因為根據(jù)對接文檔,我知道這個字段正是廣告Offer集合,一個item代表一個廣告Offer。


如何用Java反射提高開發(fā)效率的框架  


要實現(xiàn)根據(jù)注解自動將TestResponse對象解析生成List<ProdCampaign>集合,那肯定要對TestResponse對象的結構了如指掌(下文將這一類由調(diào)用API返回的對象稱為Response對象)。所以需要將TestResponse類中的字段信息映射成一顆樹。


先不講那么多,來看下最終實現(xiàn)的效果,使用@ProdCampaignMapRules注解聲明映射規(guī)則。


如何用Java反射提高開發(fā)效率的框架  



正如上圖所示,我在RowsetBean類添加@ProdCampaignMapRules注解,意味著會自動將類型為RowsetBean的對象,映射生成ProdCampaign對象。


認真看,你會發(fā)現(xiàn),TestRsponse類上面還有個注解@MapRulesComponent,它的作用只是聲明這個類支持使用自動映射。我在程序啟動時,會掃描所有被該注解注釋的Response,將這些Response解析成一棵棵類結構樹,緩存在內(nèi)存中。


實現(xiàn)自動解析API返回的廣告Offer數(shù)組,映射生成平臺統(tǒng)一的ProdCampaign集合的步驟,繼續(xù)以上圖中的例子為例。


第一步:從類結構樹中,找到有@ProdCampaignMapRules的ClassNode,再得到這個ClassNode 所屬的FieldNode。找到的FieldNode就是Response中的List<RowsetBean> rowset字段。獲取rowset的值,這就得到了廣告Offer集合。


第二步:New一個List<ProdCampaign>,遍歷廣告Offer集合rowset,將每個RowsetBean類型的元素轉為平臺統(tǒng)一的ProdCampaign對象,并添加到List<ProdCampaign>集合中。


第三步:將每個RowsetBean轉為ProdCampaign的過程當中,需要new一個ProdCampaign對象,然后給這個對象里面的字段賦值。值從哪來?從RowsetBean對象中找到與之對應的字段,并獲取值,為ProdCampaign對象賦值。很好理解,不就是屬性拷貝。


第四步:如果是多層映射,如例子中的“offer.name"映射規(guī)則,就是要先獲取到RowsetBean對象中的offer字段,類型為OfferBean。再繼續(xù)下一層name的映射,name的映射就是獲取OfferBean的name字段。這就是一個兩層映射的例子。


我定義的結構體看起來很復雜。RuleMetaData,就是完成包掃描后每個Class生成的類結構樹。類中的字段信息用FieldNode存放,如果該字段的類型是非基本數(shù)據(jù)類型,則FieldNode的child是該字段所對應類型的ClassNode數(shù)據(jù)。


如何用Java反射提高開發(fā)效率的框架

整棵結構樹就是一個RuleMetaData,根節(jié)點root肯定是一個ClassNode。非基本數(shù)據(jù)類型的FieldNode也有一個child指向一個ClassNode。很抽象?沒關系,繼續(xù)看,下面會有一張圖,形象的畫出了這棵結構數(shù)。


實現(xiàn)包掃描將Class解析成一顆結構樹


在應用啟動時,實現(xiàn)包掃描,找出所有被@MapRulesComponent注釋的類,解析生成結構樹RuleMetaData,舉個例子。



如何用Java反射提高開發(fā)效率的框架

如圖,已經(jīng)畫得很形象了,這棵樹的結構應該已經(jīng)在你的腦子里。

結構樹的root節(jié)點,是該Response的第一個字段,存儲了這個字段的字段名和反射獲取到的Field,所屬類TestResponse。下個字段就是節(jié)點的nextField字段,由于該字段的類型是基本數(shù)據(jù)類型int,所以child的值為null。

到data字段的時候,由于其類型是非基本數(shù)據(jù)類型,而是一個內(nèi)部類DtaBean,需要解析成一個ClassNode,同時要繼續(xù)反射取得DataBean的所有字段的FieldNode節(jié)點鏈。最后將data節(jié)點的child指向這個ClassNode。

在反射DataBean生成FieldNode鏈的時候,處理到rowset字段,發(fā)現(xiàn)其是一個List類型,那就獲取這個List的元素的類型,這個反射是支持的,能獲取到。

如何用Java反射提高開發(fā)效率的框架

然后再繼續(xù)對RowsetBean繼續(xù)以上步驟。還有一點,就是RowsetBean被@ProdCampaignMapRules注解注釋,所以要獲取到@ProdCampaignMapRules注解,賦值給rowset的ClassNode節(jié)點的rule。

反射解析Response生成結構數(shù),我是使用隊列加廣度優(yōu)先遍歷方法。代碼如下圖所示。

如何用Java反射提高開發(fā)效率的框架

如何用Java反射提高開發(fā)效率的框架

包掃描如何實現(xiàn)我就不說了。


根據(jù)OfferBean的Class結構樹映射生成ProdCampaign


這一步我只介紹實現(xiàn)思路,每一步的具體實現(xiàn),整體的實現(xiàn)就不貼代碼了。


1.首先使用jackson解析調(diào)用第三方API返回的json字符串,得到Response對象。


2.根據(jù)Response的Class從緩存中獲取其類結構樹。使用深度優(yōu)先搜索,取得被@ProdCampaignMapRules注釋的ClassNode。這個很好判斷,因為在前面將類生成結構樹的步驟,已經(jīng)取得@ProdCampaignMapRules注解并存放到了ClassNode的rule。


如何用Java反射提高開發(fā)效率的框架


3.獲取到被@ProdCampaignMapRules注釋的ClassNode后,取得該ClassNode所屬的FieldNode。


4.取得該FieldNode后,獲取Field,反射取得值,這個值就是要找的目標,即存放廣告Offer的集合。


如何用Java反射提高開發(fā)效率的框架


5.拿到存放廣告Offer的集合后,遍歷這個集合,將里面的每個元素,映射成平臺統(tǒng)一的存放廣告信息的ProdCampaign。最后就能獲取到ProdCampaign集合。


6.每個元素映射成ProdCampaign對象的過程,才是重點,還是很復雜的。因為需要支持多層映射,就是支持像使用mybatis拼寫sql一樣支持“.”操作,如“offer.geo.country”,就是要取得offer對象的geo字段的值,再獲取geo的country字段的值。有了類結構樹,多級映射并不難,只需要一個while循環(huán)即可。


如何用Java反射提高開發(fā)效率的框架  


7.對于tracklinkMap,是一個注解數(shù)組,類型是@TracklinkMap,用于聲明url需要哪些參數(shù),怎么拼接。


如何用Java反射提高開發(fā)效率的框架

“如何用Java反射提高開發(fā)效率的框架”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI