小試牛刀--Android AOP(面向切面編程)開發(fā)

AOP面向切面編程開發(fā)

說明

定義

把某方面的功能提出來與一批對象進行隔離栅葡,這樣與一批對象之間降低耦合性九妈,就可以對某個功能進行編程切省。

應用
  • 用戶行為統(tǒng)計
  • 權(quán)限管理
  • 其他
AOP實現(xiàn)流程
  • aspectj 框架

是一個面向切面編程框架沦泌,它有專門的編譯器用來生成java 字節(jié) 碼溉痢,生成class文件塘揣。我們使用這個框架后編譯字節(jié)碼的工具不再試javac

下載aspectj 地址: http://www.eclipse.org/aspectj/downloads.php
下載aspectj的adt地址: http://www.eclipse.org/ajdt/downloads/#43zips
aspectJ 寫法: http://fernandocejas.com/2014/08/03/aspect-oriented-programming-in-android/

  • 實現(xiàn)流程

    • 標記切點

      用注解實現(xiàn)一個標識包雀,添加到需要使用地方

    • 在切面中處理切點

      用AspectJ來實現(xiàn)切點的邏輯

    • 邏輯處理

  • 優(yōu)點
    因為用了自己編譯器生成class文件,所以注解發(fā)生在編譯時亲铡,對java性能無任何影響才写。

編碼實現(xiàn)

此處我們使用AOP實現(xiàn)方法耗時統(tǒng)計

Android studio添加AspectJ框架

  • 更改module的build 文件
//需要添加
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

apply plugin: 'com.android.application'

buildscript {
    repositories {
        mavenCentral()
    }
    //需要添加
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.9'
        classpath 'org.aspectj:aspectjweaver:1.8.9'
    }
}
repositories {
    mavenCentral()
}
android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.siqiyan.lightlu.aoptest"
        minSdkVersion 23
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
//需要添加
final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
    if (!variant.buildType.isDebuggable()) {
        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return;
    }

    JavaCompile javaCompile = variant.javaCompile
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.8",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)

        MessageHandler handler = new MessageHandler(true);
        new Main().run(args, handler);
        for (IMessage message : handler.getMessages(null, true)) {
            switch (message.getKind()) {
                case IMessage.ABORT:
                case IMessage.ERROR:
                case IMessage.FAIL:
                    log.error message.message, message.thrown
                    break;
                case IMessage.WARNING:
                    log.warn message.message, message.thrown
                    break;
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break;
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break;
            }
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.0'
    //需要添加
    compile files('libs/aspectjrt.jar')
    implementation files('libs/aspectjrt.jar')
}

  • 在module的libs目錄下導入aspectj.jar 文件


    image

創(chuàng)建注解類



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

添加標記點(在需要處理的方法使用駐點)

  • 使用注解前的代碼
/**
     * 語音的模塊
     *
     * @param view
     */
    public  void shake(View view)
    {
        long beagin=System.currentTimeMillis();

        //搖一搖的代碼邏輯
        
        SystemClock.sleep(3000);
        Log.i(TAG,"搖到一個妹子,距離500公里");
       

        Log.i(TAG,"消耗時間:  "+(System.currentTimeMillis()-beagin)+"ms");
    }

   /**
     * 搖一搖的模塊
     *
     * @param view
     */
  @BehaviorTimeTrace("搖一搖")
    public void shake(View view){
        SystemClock.sleep(3000);
        Log.i(TAG,"搖到一個妹子奖蔓,距離500公里");
    }

AOP處理

具體處理思想分為下面幾步:

  • 1.獲取標記點(獲取我們注解的方法)
  • 2.處理注解

詳細實現(xiàn):

  • 創(chuàng)建類加上@Aspect注解,創(chuàng)建切面類
    此次類所有處理代碼如下
@Aspect
public class BehaviorTimeAspect {
    SimpleDateFormat format =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static  final String TAG="AOPDemo";
    //比作切蛋糕赞草,如何切蛋糕
    //第一步獲切點,即獲得想要處理方法:* *代表所有方法吆鹤,(..)代表所有參數(shù)厨疙,這里可以根據(jù)具體的方法類型來做處理
//    @Pointcut("execution(@com.siqiyan.lightlu.aoptest.BehaviorTimeTrace  * *(..))")
    @Pointcut("execution(@com.siqiyan.lightlu.aoptest.BehaviorTimeTrace  * *(..))")
    public void insertBehavior(){

    }

     //對于想好切的蛋糕,如何吃
    //第二步處理獲取的切點
    @Around("insertBehavior()")
    public Object dealPoint(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        //獲取標記的方法
        BehaviorTimeTrace annotation = signature.getMethod().getAnnotation(BehaviorTimeTrace.class);
        //獲取標記方法名
        String value = annotation.value();

        Log.i(TAG,value+"開始使用的時間:   "+format.format(new Date()));
        long beagin=System.currentTimeMillis();
        Object proceed=null;

        try {
            //執(zhí)行方法
            proceed = proceedingJoinPoint.proceed();
        }catch (Exception e){

        }
        Log.i(TAG,"消耗時間:  "+(System.currentTimeMillis()-beagin)+"ms");

        return proceed;

    }


}
  • 獲取標記點處理
    這個方法用來處理疑务,到根據(jù)注解類找到相應的方法:獲得想要處理方法: * *代表所有方法沾凄,(..)代表所有參數(shù),這里可以根據(jù)具體的方法類型來做處理
@Pointcut("execution(@com.siqiyan.lightlu.aoptest.BehaviorTimeTrace  * *(..))")
    public void insertBehavior(){

    }
  • 處理標記點
//關(guān)聯(lián)上面的方法
  @Around("insertBehavior()")
    public Object dealPoint(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
    //固定寫法知允,用于獲取標記點
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        //獲取標記的方法
        BehaviorTimeTrace annotation = signature.getMethod().getAnnotation(BehaviorTimeTrace.class);
        //獲取標記方法名撒蟀,即我們注解傳的參數(shù)
        String value = annotation.value();

        Log.i(TAG,value+"開始使用的時間:   "+format.format(new Date()));
        long beagin=System.currentTimeMillis();
        Object proceed=null;

        try {
            //執(zhí)行我們注解的方法
            proceed = proceedingJoinPoint.proceed();
        }catch (Exception e){

        }
        Log.i(TAG,"消耗時間:  "+(System.currentTimeMillis()-beagin)+"ms");

        return proceed;

    }

效率

測試如下:


image

可以看到使用AspectJ 框架編譯時生成的字節(jié)碼,所以處理邏輯會占用更少的時間温鸽。查看編譯的源碼我們可以看到生成的class文件里面包含注解的處理保屯。

Demo源碼

源碼 AOPTest

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市涤垫,隨后出現(xiàn)的幾起案子姑尺,更是在濱河造成了極大的恐慌,老刑警劉巖蝠猬,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件股缸,死亡現(xiàn)場離奇詭異,居然都是意外死亡吱雏,警方通過查閱死者的電腦和手機敦姻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門瘾境,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人镰惦,你說我怎么就攤上這事迷守。” “怎么了旺入?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵兑凿,是天一觀的道長。 經(jīng)常有香客問我茵瘾,道長礼华,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任拗秘,我火速辦了婚禮圣絮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雕旨。我一直安慰自己扮匠,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布凡涩。 她就那樣靜靜地躺著棒搜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪活箕。 梳的紋絲不亂的頭發(fā)上力麸,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音育韩,去河邊找鬼克蚂。 笑死,一個胖子當著我的面吹牛座慰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播翠拣,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼版仔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了误墓?” 一聲冷哼從身側(cè)響起蛮粮,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谜慌,沒想到半個月后然想,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡欣范,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年变泄,在試婚紗的時候發(fā)現(xiàn)自己被綠了令哟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡妨蛹,死狀恐怖屏富,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛙卤,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站惶室,受9級特大地震影響汁讼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜行嗤,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一已日、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昂验,春花似錦捂敌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至甫恩,卻和暖如春逆济,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背磺箕。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工奖慌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人松靡。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓简僧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雕欺。 傳聞我的和親對象是個殘疾皇子岛马,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

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

  • 本章內(nèi)容: 面向切面編程的基本原理 通過POJO創(chuàng)建切面 使用@AspectJ注解 為AspectJ切面注入依賴 ...
    謝隨安閱讀 3,125評論 0 9
  • WHY 如果說OOP(面向?qū)ο蟮某绦蛟O計)的主要思想是將問題歸分到相應的對象(類)中去實現(xiàn),再把相關(guān)類模塊化使得模...
    野生大P閱讀 944評論 0 8
  • 一、簡述 1屠列、AOP的概念 如果你用java做過后臺開發(fā)啦逆,那么你一定知道AOP這個概念。如果不知道也無妨笛洛,套用百度...
    GitLqr閱讀 4,185評論 6 25
  • 昨天在花草論壇里看到有個花友問大家為什么喜歡花的問題夏志,我回答:為了參與一顆生命的成長。有花友笑話我說:養(yǎng)個花還養(yǎng)成...
    靜之般若閱讀 489評論 5 5
  • 一場突如其來的車禍苛让,留下了女兒的身體和直子的靈魂沟蔑。 平介面對擁有這直子靈魂的女兒湿诊,這扭曲了的關(guān)系,讓平介如何去應對...
    theBugKiller閱讀 217評論 0 0