Android Aop學(xué)習(xí)總結(jié)

一依啰、什么是AOP

AOP是Aspect Oriented Programming的縮寫耕餐,即『面向切面編程』。它和我們平時接觸到的OOP都是編程的不同思想旺上,OOP瓶蚂,即『面向?qū)ο缶幊獭唬岢氖菍⒐δ苣K化宣吱,對象化窃这,而AOP的思想,則不太一樣凌节,它提倡的是針對同一類問題的統(tǒng)一處理钦听,通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術(shù)。AOP是OOP的延續(xù)倍奢,是軟件開發(fā)中的一個熱點朴上,也是Spring框架中的一個重要內(nèi)容,是函數(shù)式編程的一種衍生范型卒煞。利用AOP可以對業(yè)務(wù)邏輯的各個部分進行隔離痪宰,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發(fā)的效率衣撬。

二乖订、AspectJ

適用于Aop的兼容java的一套語言

三、Aop基礎(chǔ)知識點

術(shù)語
  1. 通知具练、增強處理(Advice) 就是你想要的功能乍构。你給先定義好,然后再想用的地方用一下扛点。包含Aspect的一段處理代碼

  2. 連接點(JoinPoint)
    所有可以被通知的地方哥遮,基本每個方法的錢、后(兩者都有也行)陵究,或拋出異常是時都可以是連接點眠饮,spring只支持方法連接點。其他如AspectJ還可以讓你在構(gòu)造器或?qū)傩宰⑷霑r都行铜邮,不過那不是咱們關(guān)注的仪召,只要記住,和方法有關(guān)的前前后后都是連接點松蒜。

  3. 切入點(Pointcut) 假如你的一個類里扔茅,有15個方法,那就有十幾個連接點秸苗,但是你并不想在所有方法附件都使用通知(使用叫織入)咖摹,你只是想讓其中幾個,在調(diào)用這幾個方法之前难述、之后或者拋出異常時干點什么,那么就用切入點來定義這幾個方法吐句,讓切點來篩選連接點胁后,選中那幾個你想要的方法。

  4. 切面(Aspect) 切面是通知和切入點的結(jié)合∴率啵現(xiàn)在發(fā)現(xiàn)了吧攀芯,沒連接點什么事,鏈接點就是為了讓你好理解切點搞出來的文虏。

  5. 織入(weaving) 把切面應(yīng)用到目標對象來創(chuàng)建新的代理對象的過程侣诺。

參考此篇文章全面了解

Aop注解

@Aspect:聲明切面,標記類
@Pointcut(切點表達式):定義切點氧秘,規(guī)則定義
@Before(切點表達式):前置通知年鸳,切點之前執(zhí)行
@Around(切點表達式):環(huán)繞通知,切點前后執(zhí)行
@After(切點表達式):后置通知丸相,切點之后執(zhí)行
@AfterReturning(切點表達式):返回通知薪介,切點方法返回結(jié)果之后執(zhí)行
@AfterThrowing(切點表達式):異常通知拴测,切點拋出異常時執(zhí)行
1.@AfterThrowing通知與@AfterReturning通知是互斥的砌左,在同個切點上不可能同時出現(xiàn)浅蚪。

Aop切點表達式

基本模式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

這里問號表示當前項可以有也可以沒有,其中各項的語義如下:

  1. modifiers-pattern:方法的可見性莱没,如public,protected;
  2. ret-type-pattern:方法的返回值類型华匾,如int,void等机隙;
  3. declaring-type-pattern:方法所在類的全路徑名蜘拉,如com.spring.Aspect;
  4. name-pattern:方法名類型黍瞧,如buisinessService()诸尽;
  5. param-pattern:方法的參數(shù)類型,如java.lang.String印颤;
  6. throws-pattern:方法拋出的異常類型您机,如java.lang.Exception;

eg

execution(public * com.spring.service.BusinessObject.businessService(java.lang.String,..))

上述切點表達式將會匹配使用public修飾年局,返回值為任意類型际看,并且是com.spring.BusinessObject類中名稱為businessService的方法,方法可以有多個參數(shù)矢否,但是第一個參數(shù)必須是java.lang.String類型的方法仲闽。
通配符:

  • *通配符,該通配符主要用于匹配單個單詞僵朗,或者是以某個詞為前綴或后綴的單詞赖欣。
  • ..通配符,該通配符表示0個或多個項验庙,主要用于declaring-type-pattern和param-pattern中顶吮,如果用于declaring-type-pattern中,則表示匹配當前包及其子包粪薛,如果用于param-pattern中悴了,則表示匹配0個或多個參數(shù)。

詳細參考:
Spring AOP切點表達式用法總結(jié)

四违寿、登陸案例

1.引入AspectJ
在build.gradle中的配置

apply plugin: 'com.android.application'
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.9'
        classpath 'org.aspectj:aspectjweaver:1.8.9'
    }
}
repositories {
    mavenCentral()
}
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;
            }
        }
    }
}

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.lcc.aoplogin"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    compile 'org.aspectj:aspectjrt:1.8.9'
}

2.切面類

@Aspect
public class LoginAspect {
//定義篩選的規(guī)則湃交,所有添加了CheckLogin注解的方法都執(zhí)行邏輯
    @Pointcut("execution(@com.example.lcc.aoplogin.annotation.CheckLogin  * *(..))")
    public void executionCheckLogin() {
    }

    /**
     * 處理切面
     * @param joinPoint
     * @return
     */
    @Around("executionCheckLogin()")
    public Object checkLogin(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        CheckLogin checkLogin = signature.getMethod().getAnnotation(CheckLogin.class);
        if (checkLogin != null) {
            Context context = (Context) joinPoint.getThis();
            if (MyApplication.isLogin) {
                MyApplication.loginSdk.mLoginSuccess();
                return joinPoint.proceed();
            } else {
                MyApplication.loginSdk.mLoginFail();
                return null;
            }
        }
        return joinPoint.proceed();
    }
}

3.注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) 
public @interface CheckLogin {
}

4.MyApp中,主要是處理不同登陸狀態(tài)下的邏輯

package com.example.lcc.aoplogin;

import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyApplication extends Application {
    public static boolean isLogin;
    public static LoginInterface loginSdk;
    private Context mContext;

    @Override
    public void onCreate() {
        super.onCreate();
        loginSdk = new LoginSdk();
        mContext = getApplicationContext();
    }

    class LoginSdk implements LoginInterface {

        @Override
        public void mLoginSuccess() {
            Toast.makeText(mContext, "登陸成功", Toast.LENGTH_SHORT);
        }

        @Override
        public void mLoginFail() {
            Intent intent=new Intent(mContext, LoginActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }
    }
}

5.接口

package com.example.lcc.aoplogin;

public interface LoginInterface {
    //登陸成功
    public void mLoginSuccess();

    //登陸失敗
    public void mLoginFail();

}

6.mainActivity

package com.example.lcc.aoplogin;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import com.example.lcc.aoplogin.annotation.CheckLogin;

public class MainActivity extends AppCompatActivity {
    private Button mButton1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton1 = findViewById(R.id.button_skip_one);
        MyApplication.isLogin = false;
        mButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                test();
            }
        });
    }

    @CheckLogin
    public void test() {
        startActivity(new Intent(MainActivity.this, TwoActivity.class));
    }
}

五藤巢、其他

1.JoinPoint的作用

這個參數(shù)包含了切點的所有信息

MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String name = signature.getName(); // 方法名:test
Method method = signature.getMethod(); // 方法:public void com.example.lcc.aoplogin.MainActivity.test(android.view.View)
Class returnType = signature.getReturnType(); // 返回值類型:void
Class declaringType = signature.getDeclaringType(); // 方法所在類名:MainActivity
String[] parameterNames = signature.getParameterNames(); // 參數(shù)名:view
Class[] parameterTypes = signature.getParameterTypes(); // 參數(shù)類型:View
CheckLogin checkLogin = signature.getMethod().getAnnotation(CheckLogin.class);// 通過Method對象得到切點上的注解

六搞莺、參考資料

Android面向切面編程(AOP)
【翻譯】Android中的AOP編程
Android AOP面向切面編程詳解

git源碼
~~喵印

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市掂咒,隨后出現(xiàn)的幾起案子腮敌,更是在濱河造成了極大的恐慌阱当,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糜工,死亡現(xiàn)場離奇詭異弊添,居然都是意外死亡,警方通過查閱死者的電腦和手機捌木,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門油坝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人刨裆,你說我怎么就攤上這事澈圈。” “怎么了帆啃?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵瞬女,是天一觀的道長。 經(jīng)常有香客問我努潘,道長诽偷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任疯坤,我火速辦了婚禮报慕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘压怠。我一直安慰自己眠冈,他們只是感情好,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布菌瘫。 她就那樣靜靜地躺著蜗顽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雨让。 梳的紋絲不亂的頭發(fā)上诫舅,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機與錄音宫患,去河邊找鬼。 笑死这弧,一個胖子當著我的面吹牛娃闲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匾浪,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼皇帮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蛋辈?” 一聲冷哼從身側(cè)響起属拾,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤将谊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后渐白,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尊浓,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年纯衍,在試婚紗的時候發(fā)現(xiàn)自己被綠了栋齿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡襟诸,死狀恐怖瓦堵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情歌亲,我是刑警寧澤菇用,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站陷揪,受9級特大地震影響惋鸥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鹅龄,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一揩慕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扮休,春花似錦迎卤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至缝龄,卻和暖如春叔壤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俺亮。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工东且, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留苇倡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像示惊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子录择,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

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

  • IoC 容器 Bean 的作用域 自定義作用域?qū)崿F(xiàn) org.springframework.beans.facto...
    Hsinwong閱讀 2,461評論 0 7
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理爪幻,服務(wù)發(fā)現(xiàn)挨稿,斷路器,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • 本章內(nèi)容: 面向切面編程的基本原理 通過POJO創(chuàng)建切面 使用@AspectJ注解 為AspectJ切面注入依賴 ...
    謝隨安閱讀 3,132評論 0 9
  • 一 words and expressions 1. To understand just how audacio...
    Eliot2017閱讀 337評論 0 1
  • 市場熊市侣监,日子悠閑窃爷,在長沙認識了水哥姓蜂,參加了湖南區(qū)塊鏈聯(lián)盟的線下活動逮京,有一二百人參加,感嘆幣圈的熱度策严,知道...
    不恥下作閱讀 512評論 0 0