AOP(Aspect Oriented Programming),中文通常翻译成面向切面编程。在Java当中我们常常提及到的是OOP(Object Oriented Programming)面向对象编程。其实这些都只是编程中从不同的思考方向得出的一种编程思想、编程方法。 在开发过程中,对于很多场景可以借助AOP来完成,比如日志监控,异常处理,无侵入的在宿主中插入一些代码等。这里有一篇博文介绍的非常详细《深入理解Android之AOP》,感兴趣的可以深入阅读一下~

本文主要从实践层面来学习下AspectJ的使用,以及实际项目中中,可以给程序开发带来的方便。

AspectJ的配置

1、工程根目录build.gradle配置

buildscript {
    ...
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'org.aspectj:aspectjtools:1.8.6'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

...

2、app目录下build.gradle配置

import org.aspectj.bridge.IMessage  // 添加aspectj的相关类
import org.aspectj.bridge.MessageHandler // 添加aspectj的相关类
import org.aspectj.tools.ajc.Main // 添加aspectj的相关类

apply plugin: 'com.android.application'

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

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:26.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'

    compile 'org.aspectj:aspectjrt:1.8.6' // 添加aspectj的依赖
}

//-------------------------------------------
//-----------------添加如下代码----------------
//-------------------------------------------
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;
            }
        }
    }
}

代码编写

1、自定义切片,在People类的static静态代码块执行完成后,打印一句话。

2、自定义Pointcut && 组合Pointcut, 对MainActivity中的crash进行处理。

package com.xyzlf.aspectjdemo;

import android.util.Log;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * Created by zhanglifeng on 2017/9/20.
 */

@Aspect
public class TestAspect {

    public static final String TAG = "TestAspect";

    //@After,表示使用After类型的advice,里面的value其实就是一个poincut
    @After(value = "staticinitialization(*..People)")
    public void afterStaticInitial(){
        Log.d(TAG,"the static block is initial");
    }

    @Pointcut(value = "handler(Exception)")
    public void handleException(){

    }

    @Pointcut(value = "within(*..MainActivity)")
    public void codeInMain(){

    }

    // 这里通过&&操作符,将两个Pointcut进行了组合
    // 表达的意思其实就是:在MainActivity当中的catch代码块

    @Before(value = "codeInMain() && handleException()")
    public void catchException(JoinPoint joinPoint){
        Log.d(TAG,"this is a try catch block. " + joinPoint.toString());
    }

}

编译后MainActivity类和People类信息

1、MainActivity

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.xyzlf.aspectjdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.xyzlf.aspectjdemo.People;
import com.xyzlf.aspectjdemo.TestAspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.runtime.reflect.Factory;

public class MainActivity extends AppCompatActivity {
    public MainActivity() {
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(2130968603);
        new People();
        this.test("this is tag for test");
    }

    public void test(String test) {
        try {
            throw new IllegalArgumentException("self throw exception");
        } catch (Exception var5) {
            JoinPoint var4 = Factory.makeJP(ajc$tjp_0, this, (Object)null, var5);
            TestAspect.aspectOf().catchException(var4);
        }
    }

    static {
        ajc$preClinit();
    }
}

2、People:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.xyzlf.aspectjdemo;

import com.xyzlf.aspectjdemo.TestAspect;

public class People {
    public People() {
    }

    static {
        try {
            boolean var0 = true;
        } catch (Throwable var2) {
            if(var2 instanceof ExceptionInInitializerError) {
                throw (ExceptionInInitializerError)var2;
            }

            TestAspect.aspectOf().afterStaticInitial();
            throw var2;
        }

        TestAspect.aspectOf().afterStaticInitial();
    }
}

运行程序后日志

09-20 03:56:56.672 10847-10847/? D/TestAspect: the static block is initial
09-20 03:56:56.672 10847-10847/? D/TestAspect: this is a try catch block.)
                                               
                                               [ 09-20 03:56:56.694 10847:10847 D/         ]
                                               HostConnection::get() New Host Connection established 0xe0cb1280, tid 10847

Demo地址

地址:https://github.com/xyzlf/AspectjDemo

参考资料

1、Android AOP学习之:AspectJ实践:https://juejin.im/post/58ad3944b123db00672cdeeb

2、看 AspectJ 在 Android 中的强势插入:https://juejin.im/post/587989f48d6d810058bbae01

3、深入理解Android之AOP:http://blog.csdn.net/innost/article/details/49387395


分享到