APT和AOP在android那些事情

APT和AOP在android那些事情

業務背景

apt

大家對eventbus應該不會陌生吧,eventbus是一個非常優秀的事件總線框架,在設計模式中,有點類似觀察者模式,只不過一個升級版本的觀察者模式,並且發送跟接收是切割的,解決很多讓人頭疼的內存泄漏問。其中eventbus所用到的技術就是apt,如果大家在項目中有使用到觀察者模式,不妨用eventbus來改善一下。

aop

想象一個業務場景,業務要統計activity的啓動耗時,也就是oncreate,onstart這些生命週期方法的耗時,一種原始的方式就是在每個activity的生命週期中添加重複的代碼,比如:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        long start=System.currentTimeMillis();
        super.onCreate(savedInstanceState);  //1
        setContentView(R.layout.activity_main);
        long spend=System.currentTimeMillis()-start; //2
    }

想想一個activity那麼多生命週期,一個android項目那麼多activity,是不是很繁瑣呢。這時候aop就出場了,爲什麼不用谷歌親兒子apt呢,因爲apt一個比較大的侷限性是:無法在當前類添加刪除代碼,只能創建一個新的類。簡單點概括就是aop是一個比apt更強大的代碼生成框架。

簡介

  • APT:(Annotation Processing Tool)即註解處理器,是一種註解處理的工具,用來在編譯器掃描以及處理註解。以註解作爲橋樑,通過預先設定好的代碼規則來生成對應的Java代碼
  • AOP:AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程。所以這裏所代表的其實是一種思想,實現這個思想的技術有:ASPECTJ,ASM,JAVASIST,主要是這三個派系
    ## 對比
能力 APT AOP
創建新類 y y
修改當前類 n y
實現技術 AutoService ASPECTJ,ASM,JAVASIST
註解 y y
sdk代碼修改 n y

android打包流程

android官方文檔
build-process_2x

上一張圖中,compilers階段其實是有很多個transform組成的
4821599-9f88c2f9936af805

其中apt,aop都是作用於compilers階段apt作用於class -->.dex階段,aop作用於class-->.dex或者jar-->.dex階段。可以進一步看到aop更加強大

使用小建議

apt,aop雖然能夠減少很多重複代碼量,代碼結構優化,但是也看出來了,沒有源代碼,不利於排查問題,所以使用者一定要剋制,不是這兩個技術很黑科技就喜歡去使用,否則就是給自己的項目埋下風險。同學編寫這些apt,aop代碼的同學一定要留夠足夠的調試信息,方便後續的問題追蹤

細講apt

其實網絡上已經有很多優秀apt的案例,就不想重複的編寫這個demo.貼一個推薦的案例
apt案例

細講aop

asm實現

用來動態生成類或者增強既有類的功能,ASM是可以直接產生二進制 class 文件,也可以在類被加載入 Java 虛擬機之前動態改變類行爲,底層字節碼框架,操縱的級別是底層JVM的彙編指令級別,這要求ASM使用者要對class組織結構和JVM彙編指令有一定的瞭解。

總體思路講解

  • 註冊transform,接收編譯階段代碼的輸入,這裏主要有class和jar包
  • 使用java的jarfile接口解析jar包,並且獲得jar包裏面的class文件
 JarFile jarFile = new JarFile(inFile)
  Enumeration<JarEntry> entries = jarFile.entries()
  • 使用asm藉口解析jar包裏面的class,更改自己想要的代碼操作,建議使用asm5版本,gradle默認會有這個sdk,無需集成,示例:
ClassReader reader = new ClassReader(entryBytes)
ClassWriter classWriter = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
ClassVisitor visitor = new MyClassVisitor(classWriter)
  • 無論更改與否jar包或者class,都要將文件拷貝到下一個輸入位置,參考示例:
 File outFile = transformInvocation.outputProvider.getContentLocation(
                                    jarInput.file.absolutePath,
                                    jarInput.contentTypes,
                                    jarInput.scopes,
                                    Format.JAR)
FileUtils.copyFile(jarInput.file, outFile)

網上有一個非常好的講解,並且有示例源碼:
案例

aspectj實現

aspectj是通過註解來實現aop的切面方案,也是最容易上手的一個方案
案例

javassit實現

案例

總結

上面的講究都是引用了其他人的講解成果,後面會輸出個人編寫demo的文章,更加細緻的講解aop這塊,當然估計可能沒有我現在所引用的案例優秀,透徹。


希望我的文字能給你帶來幫助,同時也歡迎關注個人公衆號,我的所有文章第一手信息回優先發布這裏。
個人公衆號:河邊的小黑屋

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章