01.AOP(AspectOrientatedProgramming面向切面程式設計)

黑夜路口發表於2018-04-13

AOP和OOP可以對比起來進行理解。

下載aspectj  地址   http://www.eclipse.org/aspectj/downloads.php

下載aspectj的adt地址http://www.eclipse.org/ajdt/downloads/#43zips

build.gradle  aspectJ  寫法  http://fernandocejas.com/2014/08/03/aspect-oriented-programming-in-android/

Java本身是一種面相物件的設計語言,在java看來,萬物皆物件,任何事物都可以看作一個物件來處理,那麼任何一個物件所具有的任何一種功能,都可以看作一個方法,都可以進行封裝,一個功能封裝為一個方法,這個方法只用來實現這個唯一的功能,別的方法怎樣,我不需要關心,我只實現自己的功能,我的功能如何實現,外界也不需要了解,只要在需要的地方呼叫即可,符合單一職責的程式設計原則。

但是可想而知,你知道,這只是一種理想的狀態,是否真的如上所說,一個方法只要做一件事就可以呢,從大的方面來說,確實如此,但是難保沒有意外,例如冰箱的製冷功能,我可能會想為了確保製冷功能正常進行,我要在製冷過程中不斷的檢測當前溫度,當溫度低於臨界值的時候停止製冷,以達到節能減排的目的,那麼很明顯,在這個功能中加入檢測溫度的東西后,無疑已經對製冷功能造成了侵入性,單一職責原則就被破壞了,所以可以說,我們程式設計的過程其實是一個不斷的向單一職責或者其他程式設計原則不斷靠近的過程,想要真的達到這種要求,幾乎是不可能的

AOP的出現就是為了解決這個問題,AOP面向切面,何為面向切面,從java來說,每個功能都是一個整體,是一個立體的模組,而從AOP來說,它的切入點是每一個整體模組的一個面,同一個整體中可能存在相同的面來處理相同的問題,最為常見的就是android中的log,每個方法中可能需要列印log,或者是每個點選事件之前的網路監測,都要根據當前網路狀態進行是否進行網路請求的處理,或者給予使用者提示等等,當我們將這些具有相同處理邏輯的面拿出來單獨處理的時候,既能保證單一職責的完整性,也可以大大減少開發週期,以及為將來可能發生變化的業務邏輯鋪平道路

下面是簡單的程式碼實現,處理對某一功能的耗時統計和網路監測功能

01.build.gradle配置

//////////--------------------AOP配置-------------------///////////////
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()
}
//////////--------------------AOP配置-------------------///////////////

apply plugin: `com.android.application`

android {
    ......
    defaultConfig {
        .......
    }
    ......
    
    //********************** CMake 方式**********************//

}

dependencies {
    ......
}



//////////--------------------AOP配置-------------------///////////////

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;
            }
        }
    }
}
//////////--------------------AOP配置-------------------///////////////

02.在libs中新增jar包aspectjrt.jar(這個包可以在aspectj安裝目錄的lib資料夾中找到,前提是你安裝了aspectj,aspectj是一個jar包形式的安裝包)

03.註解CalculateConsume

package com.app.rzm.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by renzhenming on 2018/4/13.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CalculateConsume {
    //String value();
    //int type();
}

03.註解NetworkCheck

package com.app.rzm.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by renzhenming on 2018/4/13.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NetworkCheck {
    //String value();
    //int type();
}

04.BehaviorAspect

package com.app.rzm.aop;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import android.widget.Toast;

import com.rzm.commonlibrary.general.BaseApplication;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

/**
 * Created by renzhenming on 2018/4/13.
 * 切面
 */
@Aspect
public class BehaviorAspect {

    public static final String TAG = "BehaviorAspect";
    /**
     * 切點(指定當前要切入的是com.app.rzm.aop.CalculateConsume這個註解,* *表示任何方法名(..)表示任何引數)
     */
    @Pointcut("execution(@com.app.rzm.aop.CalculateConsume  * *(..))")
    public void ABehavior(){

    }

    /**
     * 切點(指定當前要切入的是com.app.rzm.aop.NetworkCheck這個註解,* *表示任何方法名(..)表示任何引數)
     */
    @Pointcut("execution(@com.app.rzm.aop.NetworkCheck  * *(..))")
    public void BBehavior(){

    }

    @Around("ABehavior()")
    public Object calculateTime(ProceedingJoinPoint point) throws  Throwable{
        MethodSignature signature = (MethodSignature) point.getSignature();
        CalculateConsume annotation = signature.getMethod().getAnnotation(CalculateConsume.class);
        if (annotation != null) {
            long start = System.currentTimeMillis();
            //執行方法
            Object object = point.proceed();
            long end = System.currentTimeMillis();
            //方法執行完成
            Log.i(TAG, "consume time = " + (end - start));
            return null;
        }
        return null;

    }

    @Around("BBehavior()")
    public Object checkNet(ProceedingJoinPoint point) throws  Throwable{
        MethodSignature signature = (MethodSignature) point.getSignature();
        NetworkCheck annotation = signature.getMethod().getAnnotation(NetworkCheck.class);
        if (annotation != null) {
            if (!isNetWorkConn(BaseApplication.getContext())) {
                Toast.makeText(BaseApplication.getContext(),"網路斷開",Toast.LENGTH_SHORT).show();
                return null;
            }
            Object object = point.proceed();

            return null;
        }
        return null;
    }

    //判斷網路是否連線
    public static boolean isNetWorkConn(Context context){
        ConnectivityManager manager= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info=manager.getActiveNetworkInfo();
        if(null!=info){
            return info.isConnected();
        }else {
            return false;
        }
    }
}

05.測試

package com.app.rzm.test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.app.rzm.R;
import com.app.rzm.aop.CalculateConsume;
import com.app.rzm.aop.NetworkCheck;
import com.rzm.commonlibrary.general.BaseApplication;
import com.rzm.commonlibrary.utils.LogUtils;

public class TestAOPActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_aop);
    }

    @CalculateConsume()
    public void start(View view) {
        int sum = 0;
        for (int i = 0; i < 100000000; i++) {
            sum += i;
        }
        LogUtils.e("結果是:"+sum);
    }
    @NetworkCheck()
    public void check(View view) {
        Toast.makeText(BaseApplication.getContext(),"網路正常",Toast.LENGTH_SHORT).show();
    }
}


相關文章