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

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

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

話不多說,先上圖:

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

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

APT

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

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

使用姿勢 :
1、建立一個java的Module,寫一個繼承AbstractProcessor的類

AbstractProcessor

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

Processor

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

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

apt生成代碼的路徑

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

優(yōu)點:
它的強大之處無需多言,看代表框架的源碼,你可以學(xué)到很多新姿勢。總的一句話:它可以做任何你不想做的繁雜的工作,它可以幫你寫任何你不想重復(fù)代碼。懶人福利,老司機必備神技,可以提高車速,讓你以任何姿勢漂移。它可以生成任何源代碼供你在任何地方使用,就像劍客的劍,快疾如風(fēng),無所不及。

AspectJ

代表框架: Hugo(Jake Wharton)

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

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

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

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

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

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

AOP概念圖

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

AspectJ

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

AspectjPlugin

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

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

Aspectj編織后的文件路徑

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

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

Javassist

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

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

使用姿勢
1、定義一個buildSrc module添加自定義Plugin


自定義Plugin

2、自定義Transform

自定義Transform

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

處理Task

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


Javassist操作字節(jié)碼

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

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

Javassist修改后的文件路徑

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

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

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

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

AOP

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

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

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

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

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

QQ群:AndroidMVP 555343041

更新日志:

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

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

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

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

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

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

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

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

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

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

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

Android實用技巧之:用好泛型,少寫代碼

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

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

安卓AOP實戰(zhàn):Javassist強擼EventBus

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內(nèi)容