安卓AOP三劍客:APT,AspectJ,Javassist

AOP:面向切面編程(Aspect-Oriented Programming)。如果說,OOP如果是把問題劃分到單個(gè)模塊的話,那么AOP就是把涉及到眾多模塊的某一類問題進(jìn)行統(tǒng)一管理。

Android AOP就是通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,提高開發(fā)效率。本文僅做知識(shí)介紹,相關(guān)詳細(xì)內(nèi)容不做過多描述,全部代碼在項(xiàng)目T-MVP。

話不多說,先上圖:

APT,AspectJ,Javassist對(duì)應(yīng)的編譯時(shí)期

AOP在Java后臺(tái),已經(jīng)被各路大神研發(fā)出各種框架風(fēng)生水起,例如SSH、SpringMVC等等殿堂級(jí)框架。在Android端,近年來也是異軍突起。

APT

代表框架:DataBinding,Dagger2, ButterKnife, EventBus3 、DBFlow、AndroidAnnotation

注解處理器 Java5 中叫APT(Annotation Processing Tool),在Java6開始,規(guī)范化為 Pluggable Annotation Processing。Apt應(yīng)該是這其中我們最常見到的了,難度也最低。定義編譯期的注解,再通過繼承Proccesor實(shí)現(xiàn)代碼生成邏輯,實(shí)現(xiàn)了編譯期生成代碼的邏輯。

使用姿勢(shì) :
1、建立一個(gè)java的Module,寫一個(gè)繼承AbstractProcessor的類

AbstractProcessor

2、在工具類里處理我們自定義的注解、生成代碼:

Processor

3、在Gradle中添加 dependencies annotationProcessor project(':apt')
低版本需要使用第三方插件 apply plugin: 'com.neenbedankt.android-apt'
然后apt project(':apt')

生成的源代碼在build/generated/source/apt下可以看到

apt生成代碼的路徑

難點(diǎn):
就apt本身來說沒有任何難點(diǎn)可言,難點(diǎn)一在于設(shè)計(jì)模式和解耦思想的靈活應(yīng)用,二在與代碼生成的繁瑣,你可以手動(dòng)字符串拼接,當(dāng)然有更高級(jí)的玩法用squareup的javapoet,用建造者的模式構(gòu)建出任何你想要的源代碼。
想詳細(xì)了解可以看官網(wǎng)或這篇博客:
Android 利用 APT 技術(shù)在編譯期生成代碼

優(yōu)點(diǎn):
它的強(qiáng)大之處無需多言,看代表框架的源碼,你可以學(xué)到很多新姿勢(shì)??偟囊痪湓挘核梢宰鋈魏文悴幌胱龅姆彪s的工作,它可以幫你寫任何你不想重復(fù)代碼。懶人福利,老司機(jī)必備神技,可以提高車速,讓你以任何姿勢(shì)漂移。它可以生成任何源代碼供你在任何地方使用,就像劍客的劍,快疾如風(fēng),無所不及。

AspectJ

代表框架: Hugo(Jake Wharton)

AspectJ支持編譯期和加載時(shí)代碼注入,在開始之前,我們先看看需要了解的詞匯:
Advice(通知): 典型的 Advice 類型有 before、after 和 around,分別表示在目標(biāo)方法執(zhí)行之前、執(zhí)行后和完全替代目標(biāo)方法執(zhí)行的代碼。

Joint point(連接點(diǎn)): 程序中可能作為代碼注入目標(biāo)的特定的點(diǎn)和入口。

Pointcut(切入點(diǎn)): 告訴代碼注入工具,在何處注入一段特定代碼的表達(dá)式。

Aspect(切面): Pointcut 和 Advice 的組合看做切面。例如,在本例中通過定義一個(gè) pointcut 和給定恰當(dāng)?shù)腶dvice,添加一個(gè)了內(nèi)存緩存的切面。

Weaving(織入): 注入代碼(advices)到目標(biāo)位置(joint points)的過程。

下面這張圖簡(jiǎn)要總結(jié)了一下上述這些概念。

AOP概念圖

使用姿勢(shì):
1、建立一個(gè)android lib Module,定義一個(gè)切片,處理自定義注解,和添加切片邏輯

AspectJ

2、自定義一個(gè)gradle插件,使用 AspectJ 的編譯器(ajc,一個(gè)java編譯器的擴(kuò)展),對(duì)所有受 aspect 影響的類進(jìn)行織入,在 gradle 的編譯 task 中增加額外配置,使之能正確編譯運(yùn)行。

AspectjPlugin

3、在grade中apply plugin:com.app.plugin.AspectjPlugin

生成的class文件在build/intermediates/classes下可以看到

Aspectj編織后的文件路徑

難點(diǎn):
AspectJ語法比較多,但是掌握幾個(gè)簡(jiǎn)單常用的,就能實(shí)現(xiàn)絕大多數(shù)切片,完全兼容Java(純Java語言開發(fā),然后使用AspectJ注解,簡(jiǎn)稱@AspectJ。)想詳細(xì)了解可以看官網(wǎng)或這篇博客:
深入理解AndroidAOP

優(yōu)點(diǎn):
AspectJ除了hook之外,AspectJ還可以為目標(biāo)類添加變量,接口。另外,AspectJ也有抽象,繼承等各種更高級(jí)的玩法。它能夠在編譯期間直接修改源代碼生成class,強(qiáng)大的團(tuán)戰(zhàn)切入功能,指哪打哪,鞭辟入里。有了此神器,編程亦如庖丁解牛,游刃而有余。

Javassist

代表框架:熱修復(fù)框架HotFix 、Savior(InstantRun)等

Javassist作用是在編譯器間修改class文件,與之相似的ASM(熱修復(fù)框架女媧)也有這個(gè)功能,可以讓我們直接修改編譯后的class二進(jìn)制代碼,首先我們得知道什么時(shí)候編譯完成,并且我們要趕在class文件被轉(zhuǎn)化為dex文件之前去修改。在Transfrom這個(gè)api出來之前,想要在項(xiàng)目被打包成dex之前對(duì)class進(jìn)行操作,必須自定義一個(gè)Task,然后插入到predex或者dex之前,在自定義的Task中可以使用javassist或者asm對(duì)class進(jìn)行操作。而Transform則更為方便,Transfrom會(huì)有他自己的執(zhí)行時(shí)機(jī),不需要我們插入到某個(gè)Task前面。Tranfrom一經(jīng)注冊(cè)便會(huì)自動(dòng)添加到Task執(zhí)行序列中,并且正好是項(xiàng)目被打包成dex之前。

使用姿勢(shì)
1、定義一個(gè)buildSrc module添加自定義Plugin


自定義Plugin

2、自定義Transform

自定義Transform

3、在Transform里處理Task,通過inputs拿到一些東西,處理完畢之后就輸出outputs,而下一個(gè)Task的inputs則是上一個(gè)Task的outputs。

處理Task

4、使用Javassist操作字節(jié)碼,添加新的邏輯或者修改原有邏輯


Javassist操作字節(jié)碼

5、在grade中apply plugin:com.app.plugin.MyPlugin

修改后的class文件在build/intermediates/transforms/MyTrans下可以看到

Javassist修改后的文件路徑

難點(diǎn):
相比ASM,Javassist對(duì)java極度友好的api更容易快速上手,難點(diǎn)在思想的應(yīng)用,小到切片邏輯的控制,如本例中的性能log打印日志,大到宏觀的熱修復(fù),插件化中對(duì)preDex的操作修改,劍客精神到了這一層級(jí),已經(jīng)是上帝視角,無所不能。

優(yōu)點(diǎn):
由于Javassist可以直接操作修改編譯后的字節(jié)碼,直接繞過了java編譯器,所以可以做很多突破限制的事情,例如,跨dex引用,解決熱修復(fù)中CLASS_ISPREVERIFIED的問題。

想詳細(xì)了解可以看官網(wǎng)或這篇博客:
Android熱補(bǔ)丁動(dòng)態(tài)修復(fù)技術(shù)

基于Instant Run思想的HotFix方案實(shí)現(xiàn)

AOP

AOP技術(shù)常用在以下方面:
1、日志記錄:業(yè)務(wù)埋點(diǎn)
2、持久化
3、性能監(jiān)控:性能日志
4、數(shù)據(jù)校驗(yàn):方法的參數(shù)校驗(yàn)
5、緩存:內(nèi)存緩存和持久緩存
6、權(quán)限檢查:業(yè)務(wù)權(quán)限(如登陸,或用戶等級(jí))、系統(tǒng)權(quán)限(如拍照定位)
7、異常處理

利用AOP技術(shù)將這些功能代碼從業(yè)務(wù)邏輯代碼中劃分出來,通過對(duì)這些行為的分離,可以將它們獨(dú)立到非業(yè)務(wù)邏輯。無論是日后新增,或是修改,都手到擒來易如反掌。

例如新的tmvp的demo中 apt用于生成實(shí)例化工廠,替換掉(對(duì)于小項(xiàng)目來說)繁雜冗余的Dagger2,實(shí)現(xiàn)了初始化功能的aop ;aspectj 的切片主要用在緩存和日志,用注解實(shí)現(xiàn)方法級(jí)別的內(nèi)存緩存和方法耗時(shí)日志;Javassist 這里只是做了個(gè)示例,也是通過注解實(shí)現(xiàn)方法耗時(shí)日志的自動(dòng)打印功能,當(dāng)然這些都只是AOP的九牛一毛,AOP還可以做很多事,彌補(bǔ)OOP的不足,把所有跨對(duì)象的橫切面關(guān)注點(diǎn)的功能都可以提取出來用AOP去實(shí)現(xiàn) ,好處顯而易見,將來要改的地方永遠(yuǎn)只有一處,而不是像OOP那樣牽扯很多模塊很多代碼很多類。

當(dāng)然還有更多未知的可能,需要等各位大俠來研究開發(fā),讓Aop在Android上的應(yīng)用更加廣泛。

PS:剛發(fā)現(xiàn)一個(gè)歪果仁的框架 http://6thsolution.github.io/EasyMVP 基于Clean Architecture 用了apt、aspectj、javassisit 不多說趕緊看源代碼學(xué)習(xí)去了

QQ群:AndroidMVP 555343041

更新日志:

2017/1/31:AOP新增SysPermissionAspect支持動(dòng)態(tài)申請(qǐng)系統(tǒng)權(quán)限切片,輕松適配6.0+

2017/1/27:AOP新增DbRealmAspect支持Realm數(shù)據(jù)庫,數(shù)據(jù)庫突破你想像的簡(jiǎn)單(年夜特供)

2017/1/8: 使用Apt封裝Retrofit生成ApiFactory替換掉所有的Repository,狂刪代碼

2017/1/7: 使用DataBinding替換掉所有的ButterKnife,狂刪代碼

2017/1/6: 使用DataBinding替換掉所有的ViewHolder,狂刪代碼,從此邁向新時(shí)代

2016/12/30:使用Apt生成全局路由TRouter,更優(yōu)雅的頁面跳轉(zhuǎn),支持傳遞參數(shù)和共享view轉(zhuǎn)場(chǎng)動(dòng)畫

2016/12/29:去掉BaseMultiVH新增VHClassSelector支持更完美的多ViewHolder

2016/12/28:使用Apt生成全局的ApiFactory替代所有的Model

2016/12/27:增加了BaseMultiVH擴(kuò)展支持多類型的ViewHolder

2016/12/26:抽離CoreAdapterPresenter優(yōu)化TRecyclerView

安卓AOP實(shí)戰(zhàn):面向切片編程

Android實(shí)用技巧之:用好泛型,少寫代碼

安卓AOP實(shí)戰(zhàn):APT打造極簡(jiǎn)路由

全局路由TRouter,更優(yōu)雅的頁面跳轉(zhuǎn)

安卓AOP實(shí)戰(zhàn):Javassist強(qiáng)擼EventBus

加入OkBus,實(shí)現(xiàn)注解傳遞事件

安卓AOP三劍客:APT,AspectJ,Javassist

1、去掉所有反射>2、新增apt初始化工廠,替換掉了dagger2。>3、新增aop切片,處理緩存和日志

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容