AspectJ in Android (一),AspectJ 基礎概念(轉)

AspectJ in Android 系列:

AspectJ in Android (一)搅幅,AspectJ 基礎概念

AspectJ in Android (二)热监,AspectJ 語法

AspectJ in Android (三),AspectJ 兩種用法以及常見問題

最近項目在做無埋點統(tǒng)計殃饿,解決新增功能都需要人工添加埋點的問題谋作,其中使用了 AspectJ 技術。在這過程中發(fā)現(xiàn)網(wǎng)上關于 AspectJ 在 Android 中應用的文章比較少乎芳,所以自己整理寫了 《AspectJ in Android》系列文章遵蚜,記錄自己所學的同時希望讀者可以少走一些彎路帖池。

這篇文章主要講 AspectJ 涉及到的 AOP 編程思想和 AspectJ 的一些基本概念。

AOP

什么是 AOP 吭净?

AOP (Aspect-Oriented Programming)睡汹,面向切面編程,是一種編程思想寂殉。AOP 以切面(aspect)為基礎囚巴,切面是一種新的模塊化機制,用來描述分散在對象友扰、類或函數(shù)中的橫切關點(crosscutting concern)文兢。

AOP 和我們熟悉的 OOP 面向對象編程只有一字之差,面向對象編程是以對象為基礎焕檬,把功能抽象成對象模型姆坚,優(yōu)先從對象的屬性和行為職責出發(fā),把代碼分散到一個個的類中实愚,降低代碼的復雜度同時提供復用性兼呵。但是在分散代碼時會出現(xiàn)重復代碼,例如腊敲,在兩個類的每個方法中加上日志击喂。按照 OOP 的思想,需要在方法中都加入重復的日志代碼碰辅,也許有人說把日志代碼抽象成例外一個日志的類懂昂,但是這樣的話日志類和兩個類都有耦合,而且日志類和這兩個的職責沒有關聯(lián)没宾,調(diào)用日志類的方法卻遍布兩個類的方法中凌彬。

而 AOP 的思想是把對象的核心職責外的通用邏輯(如日志,性能循衰,校驗等)抽象出來铲敛,把散布在多個對象多個模塊的通用邏輯當作切面,然后動態(tài)地把代碼插入到類的指定方法会钝、指定位置中伐蒋,實現(xiàn) AOP 的核心技術也是代碼織入技術,如 AspectJ迁酸、Javassist先鱼、DexMaker、ASMDex奸鬓、動態(tài)代理等焙畔。

所以 AOP 可以說是對 OOP 的補充,OOP 以核心職責為主從縱向劃分出一個一個類全蝶,AOP 以多個類中通用邏輯為主橫向劃分出一個一個切面闹蒜,AOP 讓 OOP 立體,去除重復代碼抑淫,降低耦合并且增加可維護性绷落。

AOP 的主要功能

AOP 是以非核心職責的通用邏輯為主的,所以主要功能是把日志記錄始苇、性能統(tǒng)計砌烁、安全控制、事務處理催式、異常處理等代碼從業(yè)務邏輯代碼中劃分出來函喉,后面再動態(tài)織入到業(yè)務邏輯中。所以 AOP 主要用于和業(yè)務邏輯相關的通用邏輯:日志記錄荣月、性能統(tǒng)計管呵、安全控制、事務處理哺窄、異常處理等等捐下。

AOP 概念

Aspect :切面,一個關注點的模塊化萌业,這個關注點可能會橫切多個對象坷襟。

Join Point :連接點,程序中可切入的點生年,例如方法調(diào)用時婴程、讀取某個變量時。

Pointcut :切入點抱婉,代碼注入的位置档叔,其實就是有條件限定的 Join Point,例如只在特定方法中注入代碼蒸绩。

Advice :在切入點注入的代碼蹲蒲,一般有 before、after侵贵、around 三種類型届搁。

Target Object :被一個或多個 aspect 橫切攔截操作的目標對象。

Weaving : 把 Advice 代碼織入到目標對象的過程窍育。

Inter-type declarations : 用來給一個類型聲明額外的方法或屬性卡睦。

AspectJ

AspectJ 是使用最為廣泛的 AOP 實現(xiàn)方案,適用于 Java 平臺漱抓,官網(wǎng)地址:http://www.eclipse.org/aspectj/ 表锻。AspectJ 是在靜態(tài)織入代碼,即在編譯期注入代碼的乞娄。

AspectJ 提供了一套全新的語法實現(xiàn)瞬逊,完全兼容 Java(跟 Java 之間的區(qū)別显歧,只是多了一些關鍵詞而已)。同時确镊,還提供了純 Java 語言的實現(xiàn)士骤,通過注解的方式,完成代碼編織的功能蕾域。因此我們在使用 AspectJ 的時候有以下兩種方式:

  • 使用 AspectJ 的語言進行開發(fā)

  • 通過 AspectJ 提供的注解在 Java 語言上開發(fā)

因為最終的目的其實都是需要在字節(jié)碼文件中織入我們自己定義的切面代碼拷肌,不管使用哪種方式接入 AspectJ,都需要使用 AspectJ 提供的代碼編譯工具 ajc 進行編譯旨巷。

在 Android Studio 上一般使用注解的方式使用 AspectJ巨缘,因為 Android Studio 沒有 AspectJ 插件,無法識別 AspectJ 的語法(不過在 Intellij IDEA 收費版上可以使用 AspectJ 插件)采呐,所以后面的語法說明和示例都是以注解的實現(xiàn)方式若锁。

引入 AspectJ

在 Android 上集成 AspectJ 比較麻煩,推薦使用 Github 上開源的 Gradle 插件 -- Android Aspectjx斧吐。該插件是利用 Gradle 的 Transform API 在項目 class 文件打包成 dex 之前進入代碼織入拴清。

首先在項目根目錄的build.gradle中添加 gradle 插件依賴:

dependencies {
    classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.0.10'
}

然后在 app 模塊的 build.gradle 添加 AspectJ 的依賴:

apply plugin: 'android-aspectjx'

dependencies {
    compile 'org.aspectj:aspectjrt:1.8.10'
}

如果把 AspectJ 代碼單獨放到一個 library module 的話,library module 還需要添加 compile 'org.aspectj:aspectjrt:1.8.+' 依賴会通。

下面是使用 android-aspectjx 插件需要注意的點:

  1. android-aspectjx 插件是 使用在 application module 的插件口予,只能在編譯 application module 的過程中織入代碼。

  2. AspectJ 的原理是在編譯期注入代碼涕侈,所以切面只能是項目代碼沪停、依賴的 jar 或 aar,不能注入 Android 平臺 android.jar裳涛。例如木张,可以在 support 包的 Fragment 中注入代碼,但是無法在 Activity 中注入代碼端三,只能注入項目的繼承自 Activity 的 XXActivity舷礼。

  3. android-aspectjx 默認會遍歷項目編譯后所有的 .class 文件和依賴的第三方庫去查找符合織入條件的切點,為了提升效率郊闯,可以加入過濾條件妻献,具體見 Android Aspectjx 的文檔。

AspectJ 示例

下面先不考慮 AspectJ 的語法团赁,先看下簡單使用 AspectJ 的示例育拨。在 Fragment 的 onResume 和 onPause 時打印 log 信息,新建一個 FragmentAspect 類:

public class FragmentAspect {

    private static final String TAG = "FragmentAspect";

    @Pointcut("execution(void android.support.v4.app.Fragment.onResume()) && target(fragment)")
    public void onResume(Fragment fragment) {}

    @Pointcut("execution(void android.support.v4.app.Fragment.onPause()) && target(fragment)")
    public void onPause(Fragment fragment) {}

    @Before("onResume(fragment)")
    public void beforeOnResume(Fragment fragment) {
        Log.d(TAG, fragment.getClass().getSimpleName() + " onResume");
    }

    @Before("onPause(fragment)")
    public void beforeOnPause(Fragment fragment) {
        Log.d(TAG, fragment.getClass().getSimpleName() + " onPause");
    }
}

這樣編譯后就可以修改在 support-v4 包中的 Fragment 類文件欢摄,通過 AspectJ 動態(tài)織入后的類會在/build/intermediates/transforms/AspectTransform/debug/jars/1/1f/aspected.jar 熬丧。

反編譯后會發(fā)現(xiàn) jar 包中有 Fragment 的代碼如下:

public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener {
    ...
    @CallSuper
    public void onResume() {
        FragmentAspect.aspectOf().beforeOnResume(this);
        this.mCalled = true;
    }

    ...
    @CallSuper
    public void onPause() {
        FragmentAspect.aspectOf().beforeOnPause(this);
        this.mCalled = true;
    }

    ...
}

可以發(fā)現(xiàn)在兩個方法前加上了打印 log 的方法,這正是 AspectJ 在日志記錄上的一個簡單示例怀挠。

這篇文章就到這里析蝴,下篇文章詳細地介紹 AspectJ 的語法害捕。

作者:JohnnyShieh
鏈接:http://www.reibang.com/p/9425be43968a
來源:簡書
著作權歸作者所有。商業(yè)轉載請聯(lián)系作者獲得授權闷畸,非商業(yè)轉載請注明出處尝盼。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市腾啥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冯吓,老刑警劉巖倘待,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異组贺,居然都是意外死亡凸舵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門失尖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啊奄,“玉大人,你說我怎么就攤上這事掀潮」娇洌” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵仪吧,是天一觀的道長庄新。 經(jīng)常有香客問我,道長薯鼠,這世上最難降的妖魔是什么择诈? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮出皇,結果婚禮上羞芍,老公的妹妹穿的比我還像新娘。我一直安慰自己郊艘,他們只是感情好荷科,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纱注,像睡著了一般步做。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奈附,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天全度,我揣著相機與錄音,去河邊找鬼斥滤。 笑死将鸵,一個胖子當著我的面吹牛勉盅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顶掉,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼草娜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了痒筒?” 一聲冷哼從身側響起宰闰,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎簿透,沒想到半個月后移袍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡老充,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年葡盗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啡浊。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡觅够,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巷嚣,到底是詐尸還是另有隱情喘先,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布廷粒,位于F島的核電站苹祟,受9級特大地震影響,放射性物質發(fā)生泄漏评雌。R本人自食惡果不足惜树枫,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望景东。 院中可真熱鬧砂轻,春花似錦、人聲如沸斤吐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽和措。三九已至庄呈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間派阱,已是汗流浹背诬留。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人文兑。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓盒刚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绿贞。 傳聞我的和親對象是個殘疾皇子因块,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,163評論 25 707
  • AspectJ in Android 系列: AspectJ in Android (一)涡上,AspectJ 基礎概...
    JohnnyShieh閱讀 4,799評論 5 23
  • 背景:公元前772年,東周周幽王烽火戲諸侯拒名,東周呈現(xiàn)四分五裂的局面吩愧。周王室勢力衰微,各國諸侯國之間開始了相互兼并的...
    淑影閱讀 237評論 1 0
  • POST是用來提交數(shù)據(jù)的隔嫡。提交的數(shù)據(jù)放在HTTP請求的正文里甸怕,目的在于提交數(shù)據(jù)并用于服務器端的存儲,而不允許用戶過...
    yuzhan550閱讀 1,290評論 1 0
  • 大明大學畢業(yè)以后和大多數(shù)人一樣留在了北京腮恩,在一家小公司里做文員梢杭,第一次見到大明是我們約好周末一起去兼職,等我到的時...
    瀏白閱讀 229評論 0 0