Android中的AOP編程

來源:知乎 欲眼熊貓

面向切面編程(AOP是Aspect Oriented Program的首字母縮寫) 设褐,我們知道啄枕,面向對象的特點是繼承萌抵、多態(tài)和封裝稿饰。而封裝就要求將功能分散到不同的對象中去缰儿,這在軟件設計中往往稱為職責分配畦粮。實際上也就是說,讓不同的類設計不同的方法乖阵。這樣代碼就分散到一個個的類中去了宣赔。這樣做的好處是降低了代碼的復雜程度,使類可重用瞪浸。 但是人們也發(fā)現(xiàn)儒将,在分散代碼的同時,也增加了代碼的重復性对蒲。什么意思呢椅棺?比如說,我們在兩個類中齐蔽,可能都需要在每個方法中做日志两疚。按面向對象的設計方法,我們就必須在兩個類的方法中都加入日志的內容含滴。也許他們是完全相同的诱渤,但就是因為面向對象的設計讓類與類之間無法聯(lián)系,而不能將這些重復的代碼統(tǒng)一起來谈况。 也許有人會說勺美,那好辦啊,我們可以將這段代碼寫在一個獨立的類獨立的方法里碑韵,然后再在這兩個類中調用赡茸。但是,這樣一來祝闻,這兩個類跟我們上面提到的獨立的類就有耦合了占卧,它的改變會影響這兩個類。那么,有沒有什么辦法华蜒,能讓我們在需要的時候辙纬,隨意地加入代碼呢?這種在運行時叭喜,動態(tài)地將代碼切入到類的指定方法贺拣、指定位置上的編程思想就是面向切面的編程。 一般而言捂蕴,我們管切入到指定類指定方法的代碼片段稱為切面譬涡,而切入到哪些類、哪些方法則叫切入點啥辨。有了AOP昂儒,我們就可以把幾個類共有的代碼,抽取到一個切片中委可,等到需要時再切入對象中去,從而改變其原有的行為腊嗡。這樣看來着倾,AOP其實只是OOP的補充而已。OOP從橫向上區(qū)分出一個個的類來燕少,而AOP則從縱向上向對象中加入特定的代碼卡者。有了AOP,OOP變得立體了客们。如果加上時間維度崇决,AOP使OOP由原來的二維變?yōu)槿S了,由平面變成立體了底挫。從技術上來說恒傻,AOP基本上是通過代理機制實現(xiàn)的。 AOP在編程歷史上可以說是里程碑式的建邓,對OOP編程是一種十分有益的補充盈厘。

** 在運行時,動態(tài)地將代碼切入到類的指定方法官边、指定位置上的編程思想就是面向切面的編程沸手。**

場景:

分離復雜度,邏輯事務與非邏輯事務分離
具體場景有:

  • 日志收集注簿;
  • 權限驗證契吉;
  • 數(shù)據(jù)驗證;
  • 監(jiān)控诡渴;
  • 更多
    邏輯代碼與非邏輯代碼示例

基本需要了解的概念

Join Points

JPoints就是程序運行時的一些執(zhí)行點捐晶。那么,一個程序中,哪些執(zhí)行點是JPoints呢租悄?比如:
  l  一個函數(shù)的調用可以是一個JPoint谨究。比如Log.e()這個函數(shù)。e的執(zhí)行可以是一個JPoint泣棋,而調用e的函數(shù)也可以認為是一個JPoint胶哲。
  l  設置一個變量,或者讀取一個變量潭辈,也可以是一個JPoint鸯屿。比如Demo類中有一個debug的boolean變量。設置它的地方或者讀取它的地方都可以看做是JPoints把敢。

我們經臣陌冢看到的依賴注入經常是這樣用的:

    @BindView(R.id.textView_commend_2)
    CommonTabLayout tl_2;

    @OnClick(R.id.textView_commend_2)
    public void onClickAdd() {
          //在該方法運行時  也是執(zhí)行點
    }

上面代碼的作用相信大家都知道,那么在這里 設置變量tl_2 時是執(zhí)行點修赞,聲明方法onClickAdd 也是執(zhí)行點婶恼。
甚至 我做一個操作 ,比如點擊一個按鈕柏副,這個按鈕會執(zhí)行onClickAdd方法勾邦,那么在我調用 onClickAdd方法之前可以是執(zhí)行點、在執(zhí)行onCLickAdd的過程中也可以是執(zhí)行點割择。
這段話說的有點繞口眷篇,如果沒有表達清楚,請見諒荔泳。

<center> AspectJ中的Join Point </center>

Join Points 說明 示例
method call 函數(shù)調用 比如調用Log.e()蕉饼,這是一處JPoint
method execution 函數(shù)執(zhí)行 比如Log.e()的執(zhí)行內部,是一處JPoint玛歌。注意它和method call的區(qū)別昧港。method call是調用某個函數(shù)的地方。而execution是某個函數(shù)執(zhí)行的內部支子。
constructor call 構造函數(shù)調用 和method call類似
constructor execution 構造函數(shù)執(zhí)行 和method execution類似
field get 獲取某個變量 比如讀取DemoActivity.debug成員
field set 設置某個變量 比如設置DemoActivity.debug成員
pre-initialization Object在構造函數(shù)中做得一些工作慨飘。
initialization Object在構造函數(shù)中做得工作
static initialization 類初始化 比如類的static{}
handler 異常處理 比如try catch(xxx)中,對應catch內的執(zhí)行
advice execution 這個是AspectJ的內容 我自己也不太懂

Pointcuts

Pointcuts是什么呢译荞? Pointcuts的功能 是從眾多的 JoinPoint中找到指定的執(zhí)行點瓤的;

在上面的代碼中 我可以通過注解拿到 變量和方法;然而通過上面的解釋我們知道一個變量或者方法存在好多個執(zhí)行點吞歼,我方法在即將執(zhí)行之前是執(zhí)行點圈膏,執(zhí)行過程中也可以是個執(zhí)行點,set變量是執(zhí)行點篙骡,get變量也是執(zhí)行點稽坤,那么我拿到了變量或者方法丈甸,我在什么時候做事情呢? 我通過什么判斷呢尿褪? Pointcuts就是做這個事情的睦擂。

** 白話:pointCuts 的作用是找到指定的注解,通過注解拿到聲明的 變量或者方法杖玲,然后設置 變量/方法 在指定的執(zhí)行點 joinPoint 顿仇。**
然后我們就可以在 指定的執(zhí)行點下做我們自定義的一系列動作。

通過注解拿到聲明的變量或者方法

** Pointcuts的目標是提供一種方法使得開發(fā)者能夠選擇自己感興趣的JoinPoints摆马。**

pointcuts中最常用的選擇條件和Joinpoint的類型密切相關


切點對應的執(zhí)行點

題目: 小明的舊娃娃質量不好臼闻,沒用幾下折騰幾下就破掉了,小明很郁悶囤采,然后小明去買新娃娃述呐,這個店家給他推薦了一個蒼老師版本的娃娃,小明在付款的時候突然想到舊娃娃的質量不好蕉毯,提出要驗驗貨乓搬。‘

** 答案:**

    @Pointcut("execution(@com.wenld.aspectjdemo.買娃娃  * *(..))")
    public void executionAspectJ() {
          驗貨...嘿嘿嘿
          if(驗貨通過) 買
    }

聲明我們要找的買娃娃 注解代虾,注解找到的方法 選擇蒼老師款+付款execution)的時候 进肯,executionAspectJ驗驗貨....

advice和aspect

恭喜,看到這個地方來褐着,AspectJ的核心部分就掌握一大部分了。現(xiàn)在托呕,我們知道如何通過pointcuts來選擇合適的JPoint含蓉。那么,下一步工作就很明確了项郊,選擇這些JPoint后馅扣,我們肯定是需要干一些事情的。比如前面例子中的 before 小明驗貨之類的着降。這其實JPoint在執(zhí)行前差油,執(zhí)行后,都執(zhí)行了一些我們設置的代碼蓄喇。

advice的類型

關鍵詞 說明 示例
before() before advice 表示在JPoint執(zhí)行之前交掏,需要干的事情
after() after advice 表示JPoint自己執(zhí)行完了后妆偏,需要干的事情盅弛。
after():returning(返回值類型) after():throwing(異常類型) returning和throwing后面都可以指定具體的類型钱骂,如果不指定的話則匹配的時候不限定類型 假設JPoint是一個函數(shù)調用的話叔锐,那么函數(shù)調用執(zhí)行完有兩種方式退出见秽,一個是正常的return,另外一個是拋異常解取。 注意步责,after()默認包括returning和throwing兩種情況
返回值類型 around() before和around是指JPoint執(zhí)行前或執(zhí)行后備觸發(fā),而around就替代了原JPoint around是替代了原JPoint肮蛹,如果要執(zhí)行原JPoint的話,需要調用proceed

在Android 中AOP工具和庫

  • AspectJ: 一個 JavaTM 語言的面向切面編程的無縫擴展(適用Android)伦忠。

  • Javassist for Android: 用于字節(jié)碼操作的知名 java 類庫 Javassist 的 Android 平臺移植版。

  • DexMaker: Dalvik 虛擬機上气忠,在編譯期或者運行時生成代碼的 Java API赋咽。

  • ASMDEX: 一個類似 ASM 的字節(jié)碼操作庫,運行在Android平臺脓匿,操作Dex字節(jié)碼。

在Android 中AOP的使用

這里使用 AspectJ:

  • 功能強大
  • 支持編譯期和加載時代碼注入
  • 易于使用

先要裝ASpectJ環(huán)境 項目中有安裝包米母,在下圖位置

AspectJ安裝包

安裝AspectJ命令 Java -jar Aspectj-xxx.jar ;
path 配置環(huán)境變量 c:\xxx\aspectjxx\bin毡琉;

環(huán)境搭建好以后
其中還要在gradle內配置一些東西,具體詳細請看代碼慧耍,這里就不貼了丐谋。

注解類 AspectJAnnotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AspectJAnnotation {
    String value();
}

執(zhí)行類AspectJTest

/**
 * <p/>
 * Author: 溫利東 on 2017/3/2 16:07.
 * blog: http://blog.csdn.net/sinat_15877283
 * github: https://github.com/LidongWen
 */
@Aspect
public class AspectJTest {
    private static final String TAG = "tag00";

    @Pointcut("execution(@com.wenld.aspectjdemo.AspectJAnnotation  * *(..))")
    public void executionAspectJ() {

    }

    @Around("executionAspectJ()")
    public Object aroundAspectJ(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Log.i(TAG, "aroundAspectJ(ProceedingJoinPoint joinPoint)");
        AspectJAnnotation aspectJAnnotation = methodSignature.getMethod().getAnnotation(AspectJAnnotation.class);
        String permission = aspectJAnnotation.value();
        if(permission.equals("權限A")) {
           Object result=joinPoint.proceed();
            Log.i(TAG, "有權限:"+permission);
            return result;
        }
        return "";
    }
}

MainActivity

    @AspectJAnnotation(value = "權限A")
    public String test() {
        Log.i(TAG, "檢查權限");
        return "test";
    }

編譯完成后 會發(fā)現(xiàn)多了一個 MainActivity$AjcClosure1.class 類:

MainActivity.class


你會發(fā)現(xiàn) 注入了一些方法号俐;

示例源碼地址:https://github.com/LidongWen/AspectJDemo/tree/master


** 一些資料地址:**
https://en.wikipedia.org/wiki/AOP
l http://www.eclipse.org/aspectj/ <=AspectJ官方網站
l http://www.eclipse.org/aspectj/doc/released/runtime-api/index.html <=AspectJ類庫參考文檔,內容非常少
l http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/index.html <=@AspectJ文檔践美,以后我們用Annotation的方式最多洗贰。
AspectJ語法
http://www.eclipse.org/aspectj/doc/released/quick5.pdf 或者官方的另外一個文檔也可以:
http://www.eclipse.org/aspectj/doc/released/progguide/semantics.html


github: LidongWen
人生得意須盡歡, 桃花塢里桃花庵
點個關注唄陨倡,對,不信你點試試绎晃?
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末杂曲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子擎勘,更是在濱河造成了極大的恐慌,老刑警劉巖棚饵,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噪漾,死亡現(xiàn)場離奇詭異,居然都是意外死亡欣硼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門豹障,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耘斩,“玉大人桅咆,你說我怎么就攤上這事⊙冶” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵版述,是天一觀的道長寞冯。 經常有香客問我晚伙,道長俭茧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任午磁,我火速辦了婚禮毡们,結果婚禮上,老公的妹妹穿的比我還像新娘衙熔。我一直安慰自己,他們只是感情好挺据,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布脖隶。 她就那樣靜靜地躺著,像睡著了一般婉称。 火紅的嫁衣襯著肌膚如雪构蹬。 梳的紋絲不亂的頭發(fā)上庄敛,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天藻烤,我揣著相機與錄音,去河邊找鬼怖亭。 笑死,一個胖子當著我的面吹牛期吓,可吹牛的內容都是我干的倾芝。 我是一名探鬼主播箭跳,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼潭千,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了脊岳?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤奶躯,失蹤者是張志新(化名)和其女友劉穎亿驾,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體儡蔓,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡疼邀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年旁振,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拐袜。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖尝哆,靈堂內的尸體忽然破棺而出甜攀,到底是詐尸還是另有隱情,我是刑警寧澤赴邻,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布姥敛,位于F島的核電站瞎暑,受9級特大地震影響与帆,放射性物質發(fā)生泄漏墨榄。R本人自食惡果不足惜玄糟,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一阵翎、第九天 我趴在偏房一處隱蔽的房頂上張望之剧。 院中可真熱鬧郭卫,春花似錦背稼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至童太,卻和暖如春胸完,著一層夾襖步出監(jiān)牢的瞬間书释,已是汗流浹背赊窥。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工锨能, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人址遇。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓倔约,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钾军,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容