Android AOP編程實現登錄檢驗

AOP概念:

把我們某個方面的功能提出來與一批對象進行隔離,這樣與一批對象之間的耦合度就降低了,就只需要對某個功能進行編程。例如android中的登陸權限問題,只需要在特定的方法加入我們的登陸切點,在不改變業務邏輯的情況下可以變更我們判斷登錄 的業務邏輯,這樣就達到了鬆耦合的目的。在編譯成.class時注入

基礎知識

AspectJ

是一個面向切面編程的框架,他擴展了java語言所以他有一個專門的編譯器用來生成遵循java字節碼規範的Class文件

aspect:切面      [整個程序塊]

Pointcut:切點    [進行切分的線]

Around:處理

註解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

 定義一個註解都要包含 @Target @Retention

@Target  標識運用在哪裏(是方法/類/....)

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

@Retention 運行在哪個地方  Source 註解僅存在於源碼中,在class字節碼文件中不包含

                                                class   默認的保留策略,註解會在class字節碼文件中存在,但運行時無法獲得

                                                runtime  註解會在class字節碼文件中存在,在運行時可以通過反射獲取到

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

 

案例

下面將以一個簡單的案例來分析登錄的註解情況。

實現VIP登錄校驗,並彈出toast

gradle引入AspectJ

app.gradle中
apply plugin: 'com.android.application'
apply plugin: 'android-aspectjx'


compile 'org.aspectj:aspectjrt:1.8.13'


project.gradle中
 dependencies {
   classpath 'com.android.tools.build:gradle:3.0.1'
   classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'
}

定義註解:

/**
 * @author crazyZhangxl on 2019/1/28.
 * Describe: 需要登陸驗證的切點 注意在interface前加入@
 */

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

定義切點切面以及特定的處理:

/**
 * @author crazyZhangxl on 2019/1/28.
 * Describe: 切面
 */
@Aspect
public class LoginAspect {

    /**
     * 對含有某個方法的特定註解打上切點
     */
    @Pointcut("execution(@com.example.aopproject.login_demo.LoginTrace * *(..))")
    public void pointCutLogin(){

    }

    /**
     * 處理 特定的打上切點的方法
     * @param proceedingJoinPoint
     * @throws Throwable
     */
    @Around("pointCutLogin()")
    public void aroundLogin(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        if (UserCache.getInstance().isLogin()){
            proceedingJoinPoint.proceed();
        }else {
            Toast.makeText(MyApp.getmContext(), "請先進行登陸!", Toast.LENGTH_SHORT).show();
        }

    }
}

 方法業務邏輯 

    @LoginTrace()
    private void methodTwo(){
        Toast.makeText(this, "執行VIP動作", Toast.LENGTH_SHORT).show();
    }

具體的運行效果:

在登錄的情況下進行VIP瀏覽操作成功,而若在未登錄的情況下操作時那麼會進行彈框提示。

 

優化:

上一個案例只是最簡單的加了aop方法運行時的處理,下面將進行拓展,讓外部去實現具體需要在未登錄的情況下去執行哪些處理

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginTrace {
    int type();
}
    /**
     * 處理 特定的打上切點的方法
     * @param proceedingJoinPoint
     * @throws Throwable
     */
    @Around("pointCutLogin()")
    public void aroundLogin(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        if (UserCache.getInstance().isLogin()){
            proceedingJoinPoint.proceed();
        }else {
            if (proceedingJoinPoint.getThis() instanceof Context){
                // 獲得註解參數
                MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
                LoginTrace annotation = signature.getMethod().getAnnotation(LoginTrace.class);
                int type = annotation.type();

                dealWithType(type,(Context) proceedingJoinPoint.getThis());
            }
        }
    }

    /**
     * 在這裏處理是彈出dialog呢還是跳轉界面呢 等等
     * @param type
     * @param context
     */
    private void dealWithType(int type,Context context){
        switch (type){
            case 0:
                Intent intent = new Intent(context,LoginActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
                break;
                default:
                    Toast.makeText( context,"請先進行登陸!", Toast.LENGTH_SHORT).show();
                    break;
        }
    }

參考資料:

AOP——Android通過AspectJ實現登錄檢驗

Android使用AOP做登錄攔截

項目完整代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章