Aop編程是一種區(qū)別OOP編程的概念豺裆,從切面的角度看待問題拒秘,這篇文章主要講述了Java開發(fā)中常用的Aop開發(fā)方式以及他們的優(yōu)缺點(diǎn)和區(qū)別号显。
什么是Aop編程
AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程躺酒,通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)押蚤。
AOP是OOP的延續(xù),是軟件開發(fā)中的一個(gè)熱點(diǎn)羹应,也是spring框架中的一個(gè)重要內(nèi)容揽碘,是函數(shù)式編程的一種衍生范型。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離园匹,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低雳刺,提高程序的可重用性,同時(shí)提高了開發(fā)的效率裸违。
常見的使用場(chǎng)景
性能監(jiān)控: 在方法調(diào)用前后記錄調(diào)用時(shí)間掖桦,方法執(zhí)行太長(zhǎng)或超時(shí)報(bào)警。
緩存代理: 緩存某方法的返回值供汛,下次執(zhí)行該方法時(shí)枪汪,直接從緩存里獲取。
軟件破解: 使用AOP修改軟件的驗(yàn)證類的判斷邏輯怔昨。
記錄日志: 在方法執(zhí)行前后記錄系統(tǒng)日志料饥。
工作流系統(tǒng): 工作流系統(tǒng)需要將業(yè)務(wù)代碼和流程引擎代碼混合在一起執(zhí)行,那么我們可以使用AOP將其分離朱监,并動(dòng)態(tài)掛接業(yè)務(wù)岸啡。
權(quán)限驗(yàn)證: 方法執(zhí)行前驗(yàn)證是否有權(quán)限執(zhí)行當(dāng)前方法,沒有則拋出沒有權(quán)限執(zhí)行異常赫编,由業(yè)務(wù)代碼捕捉巡蘸。
如果對(duì)Aop的概念不理解,可以參考文章Aop那些事
JAVA中Aop的具體實(shí)現(xiàn)方式
1擂送、JDK動(dòng)態(tài)代理
有過java開發(fā)經(jīng)驗(yàn)的朋友都知道悦荒,java通過實(shí)現(xiàn)InvocationHandler接口,可以實(shí)現(xiàn)對(duì)一個(gè)類的動(dòng)態(tài)代理嘹吨,通過動(dòng)態(tài)代理搬味,我們可以生成代理類從而在代理類方法中,在執(zhí)行被代理類方法前后蟀拷,添加自己的實(shí)現(xiàn)內(nèi)容碰纬,從而實(shí)現(xiàn)Aop。
優(yōu)點(diǎn):動(dòng)態(tài)代理java自身支持问芬,不需要引入外部庫(kù)悦析,在運(yùn)行期通過接口動(dòng)態(tài)生成代理類
缺點(diǎn):首先代理類必須實(shí)現(xiàn)一個(gè)接口,如果沒實(shí)現(xiàn)接口會(huì)拋出一個(gè)異常此衅。第二性能影響强戴,因?yàn)閯?dòng)態(tài)代理使用反射的機(jī)制實(shí)現(xiàn)的亭螟,首先反射肯定比直接調(diào)用要慢
2、動(dòng)態(tài)字節(jié)碼生成
在運(yùn)行期骑歹,目標(biāo)類加載后预烙,動(dòng)態(tài)構(gòu)建字節(jié)碼文件生成目標(biāo)類的子類,將切面邏輯加入到子類中道媚,沒有接口也可以織入默伍,但擴(kuò)展類的實(shí)例方法為final時(shí),則無法進(jìn)行織入衰琐。
可以使用Cglib來實(shí)現(xiàn)動(dòng)態(tài)字節(jié)碼生成,這是一個(gè)強(qiáng)大的炼蹦,高性能羡宙,高質(zhì)量的Code生成類庫(kù),它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口掐隐。CGLIB包的底層是通過使用一個(gè)小而快的字節(jié)碼處理框架ASM狗热,來轉(zhuǎn)換字節(jié)碼并生成新的類。
優(yōu)點(diǎn):可以織入沒有接口的類虑省;運(yùn)行時(shí)生成匿刮,減少不必要的生成開銷;通過字節(jié)碼生成子類探颈,而不是反射方式去調(diào)用代理類
缺點(diǎn):不能織入final方法熟丸;運(yùn)行時(shí)生成子類,說明會(huì)有生成開銷伪节,并且可能生成大量子類
3光羞、自定義類加載器
在運(yùn)行期,目標(biāo)加載前怀大,將切面邏輯加到目標(biāo)字節(jié)碼里纱兑。
可以對(duì)絕大部分類進(jìn)行織入,但代碼中如果使用了其他類加載器化借,則這些類將不會(huì)被織入潜慎。
Javassist是一個(gè)編輯字節(jié)碼的框架,可以讓你很簡(jiǎn)單地操作字節(jié)碼蓖康。它可以在運(yùn)行期定義或修改Class铐炫。使用Javassist實(shí)現(xiàn)AOP的原理是在字節(jié)碼加載前直接修改需要切入的方法。這比使用Cglib實(shí)現(xiàn)AOP更加高效蒜焊,并且沒太多限制.
優(yōu)點(diǎn):可以織入絕大部分類驳遵;運(yùn)行時(shí)生成,減少不必要的生成開銷山涡;通過將切面邏輯寫入字節(jié)碼堤结,減少了生成子類的開銷唆迁,不會(huì)產(chǎn)生過多子類
缺點(diǎn):運(yùn)行時(shí)加入切面邏輯,產(chǎn)生開銷竞穷;
4唐责、ASM
ASM 是一個(gè) Java 字節(jié)碼操控框架。它能夠以二進(jìn)制形式修改已有類或者動(dòng)態(tài)生成類瘾带。ASM 可以直接產(chǎn)生二進(jìn)制 class 文件鼠哥,也可以在類被加載入 Java 虛擬機(jī)之前動(dòng)態(tài)改變類行為。ASM 從類文件中讀入信息后看政,能夠改變類行為朴恳,分析類信息,甚至能夠根據(jù)用戶要求生成新類允蚣。
從上面的描述可以看出于颖,ASM可以在編譯期直接修改編譯出的字節(jié)碼文件,也可以像javassit一樣嚷兔,在運(yùn)行期森渐,類文件加載前,去修改字節(jié)碼。兩者的區(qū)別在于,一個(gè)將所有需要AOP的類都事先修改了皆刺,一個(gè)在運(yùn)行時(shí)需要才去修改。
優(yōu)點(diǎn):可以織入絕所有類耐齐;兩者生成方式,可以根據(jù)需求選擇
缺點(diǎn):修改字節(jié)碼蒋情,需要對(duì)class文件比較熟悉蚪缀,編寫過程復(fù)雜
5、AspectJ
AspectJ是一個(gè)面向切面的框架恕出,它擴(kuò)展了Java語(yǔ)言询枚。AspectJ定義了AOP語(yǔ)法所以它有一個(gè)專門的編譯器用來生成遵守Java字節(jié)編碼規(guī)范的Class文件。
和ASM一樣浙巫,Aspectj有靜態(tài)編譯和動(dòng)態(tài)編譯的優(yōu)點(diǎn)金蜀,供程序員選擇。另外Aspectj其編碼更為簡(jiǎn)潔的畴,是Android開發(fā)中渊抄,實(shí)現(xiàn)AOP的首選。
優(yōu)點(diǎn):可以織入絕所有類丧裁;兩者生成方式护桦,可以根據(jù)需求選擇;編寫簡(jiǎn)單煎娇,功能強(qiáng)大
缺點(diǎn):需要使用ajc編譯器編譯二庵,ajc編譯器是java編譯器的擴(kuò)展贪染,具有其所有功能
6、APT
自定義一個(gè)AbstractProcessor催享,在編譯期去解析編譯的類杭隙,并且根據(jù)需求生成一個(gè)實(shí)現(xiàn)了特定接口的子類(代理類),和JDK動(dòng)態(tài)代理不同的是因妙,代理類是在編譯期生成的痰憎。常見的一些Android的IOC框架中有大量應(yīng)用(就是通過注解代替findviewbyid等方法)。
詳情可以參考 Android 打造編譯時(shí)注解解析框架 這只是一個(gè)開始
這里順便說一句攀涵,目前Android注解解析框架主要有兩種實(shí)現(xiàn)方法铣耘,一種是運(yùn)行期通過反射去解析當(dāng)前類,注入相應(yīng)要運(yùn)行的方法以故,一種是在編譯期生成類的代理類蜗细,在運(yùn)行期直接調(diào)用代理類的代理方法。APT指的是后者据德。
這兩種實(shí)現(xiàn)方式,后者消耗更少跷车,但是會(huì)生成大量代理類棘利。
優(yōu)點(diǎn):可以織入絕所有類;編譯期代理朽缴,減少運(yùn)行時(shí)消耗
缺點(diǎn):需要使用apt編譯器編譯善玫;需要手動(dòng)拼接代理的代碼(其實(shí)是整個(gè)字符串);生成大量代理類
寫在最后
JAVA中AOP有多種實(shí)現(xiàn)方式密强,各有優(yōu)缺點(diǎn)茅郎,在實(shí)際項(xiàng)目中,我選擇了AspectJ或渤,因?yàn)樗膭?dòng)靜結(jié)合和編寫簡(jiǎn)單系冗,網(wǎng)上也有不少使用AspectJ來實(shí)現(xiàn)Android AOP的框架,例如https://github.com/JakeWharton/hugo薪鹦。
作者:六_六
鏈接:http://www.reibang.com/p/ffd534098e7d
來源:簡(jiǎn)書
著作權(quán)歸作者所有掌敬。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處池磁。