本文同步自wing的地方酒館
最近博客更新越來越慢了,有兩方面原因:
1.沒啥好寫的。
2.應該沉下心好好沉澱自己,積累一些東西,博客寫的太頻繁有”刷博客“之嫌,還容易浮躁。
浮躁是大忌 ,所以還是沉下心好好學吧。
網上已經有了很多類似的文章,這裏再寫一次是爲了自己當做筆記,主要是對APT,AspectJ、Javassist的簡單實用進行記錄,方便以後翻閱。
AOP是什麼這裏不多作解釋了,個人理解總結下來就是相對於各個垂直深入的業務邏輯,每個業務邏輯深度的某個層面他們有需要共同的特徵,此時對這種特徵進行統一的處理,也就是所謂的AOP(歡迎拍磚哈,技術在討論中提升)
主要應用場景:
- 權限檢查
- 日誌記錄
- 性能監控
- 埋點操作
Android 下一些可以進行AOP的工具
APT
在編譯時生成 .java 文件。
代表作品 ButterKnife 、 DataBinding、 EventBus3、Dagger2 等。
AspectJ
在.java編譯爲.class的時候,進行代碼注入。
代表作品: Hugo
Javassist
對已經編譯好的class文件進行操作。
代表作品: 各類熱修復框架(爲了解決類校驗問題)。
各個工具操作時機圖
這裏盜一張圖。原圖地址:http://www.jianshu.com/p/dca3e2c8608a
具體用法
APT
APT是編譯時生成代碼的技術, 主要用到了註解 以及處理註解的Process
這裏我寫一個簡單的小例子,來展示如何使用APT,這個例子類似於MVPHelper的功能,但其實是沒有什麼亂用的,只是展示而已。
- 建立一個module 用於聲明註解。
這裏Contract註解,是爲了標註一個Activity需要使用MVP模式。並且需要自動生成MVP代碼。
- 再建立另一個module 用於處理這些註解。
注意這裏必須是java庫,也就是說gradle要apply java 插件,否則將引用不到javax包下的內容。
這個時候,我們只需要讓ConrtactProcessor 繼承 AbstractProcess,並且實現process函數去處理這個註解即可。
這裏生成代碼使用了Javapoet, 我們的目標是在Activity上面使用@Contract註解自動生成MVP代碼,並且@Inject自動注入presenter,如下圖:
這些紅掉的代碼,就是我們想要利用APT生成的代碼,@Inject 用於表示注入mPresenter,這樣就不用我們自己new了,當然這裏是最簡單的注入展示。 我們反過來想想,想讓這些代碼可以工作,生成的代碼應該是怎樣的。生成的代碼路徑如下所示:
MVP部分的代碼不多說,來說一說presenter是如何注入的,其實很簡單:
結合上面紅色的代碼看,應該會一目瞭然吧。
關於如何生成代碼,只需要在process方法中使用javapoet即可,代碼比較簡單繁瑣,這裏就不貼了,有需要的可以到文章尾部的鏈接查看代碼。
AspetJ
AspetJ的引入比較簡單,主要是滬江公司對AspetJ進行了一些Android方面的適配。
在gradle添加
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.0.10'
以及
apply plugin: 'android-aspectjx'
使用的時候,只需要新建一個類,並且使用@Aspect註解,即可對需要hook的類生效,並且無需直接使用。
因爲在看這個之前有在用Xposed,所以感覺兩個很像,上手很快。
我們將要使用這個工具實現Activity 啓動時間的監控,以及登錄權限管理的注入,以往判斷用戶登錄往往需要每個函數都判斷一下最後執行邏輯,其實這完全可以注入進去,就像”切面“所說,需要登錄的地方,一刀切。
實現Activity啓動時間監控,這裏寫簡單一點,單純的從onCreate開始到onResume結束進行計時操作。
另外一個是登錄檢驗操作,我們理想的事情是給一個函數添加一個註解,並且這個註解來判斷是否登錄執行相應的轉跳提示操作。
示意如下,比如onResume需要判斷是否登錄,只需要一個註解
我們把需要的邏輯判斷寫在@AspetJ 註解的類裏即可。
這樣不管是埋點還是性能監控還是登錄權限檢驗,都可以異常方便的執行。再也不像原先那樣麻煩了。
Javassist
這個需要結合自定義gradle plugin一起操作,大家都知道apk編譯的時候,先把java編譯爲class文件,接下來會變爲dex文件,gradle提供了transform api,可以讓我們class變爲dex之前做任何想做的事情。
首先建立一個buildSrc的module,這裏面創建的類都是groovy的類,所以擴展名要寫groovy。至於內容嘛。。因爲兼容java 隨便你咯-。-
創建一個Plugin,叫做Regsiter, 只需要讓他implement Plugin 插件即可, 此時重寫apply方法,就可以在主工程中apply這個插件。
另外我們需要結合transform, 所以要給android插件註冊一下transform
在transform裏,我們就可以對所有文件進行操作了
ClassInjector 主要是使用Javassist進行對class文件的改變操作。
值得注意的是,如果操作的過程中需要使用android sdk內容,需要手動將 android.jar添加到 ClassPool裏面。否則會提示找不到類的情況。
本文涉及Demo代碼地址
https://github.com/githubwing/AopDemo
歡迎加入Android地方酒館(425983695)一起研究Android技術。
參考文章
1.http://www.jianshu.com/p/dca3e2c8608a
2.http://blog.csdn.net/eclipsexys/article/details/54425414
3.http://blog.csdn.net/u010386612/article/details/51131642