Android知识点

AOP编程

2018-04-20  本文已影响1人  优疏

一、基本概念介绍

AOP全称Aspect Oriented Programming,即面向切面编程。通过预编译方式或者运行期动态代理等实现程序功能统一维护的一种技术,利用AOP可以实现对业务逻辑中不同部分进行分离,从而降低耦合,提高程序的可复用性,主要用于实现日志记录、性能统计、埋点统计、安全控制、异常处理等。

在没有AOP之前,如果各个模块都要打印日志,就要自己处理,都要认为编写日志代码。若以后日志模块修改API,则使用它们的地方都要改。AOP的目标就是解决上述提到的这种麻烦的问题。AOP的目标就是把这些功能集中起来,放在一个统一的地方来控制和管理。比如我们可以设置Aspect,来管理软件中一些特殊函数调用的权限问题,如检验登录流程等。

1.术语

2.AOP织入类型

二、AspectJ实现AOP

AspectJ功能强大,支持编译期的代码织入,不影响应用的性能,同时提供易于使用的API。

1.AspectJ基本使用

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'org.aspectj:aspectjtools:1.8.1'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
apply plugin: 'com.android.library'
import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.3"

    defaultConfig {
        minSdkVersion 14
        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'
        }
    }
}

android.libraryVariants.all { variant ->
    LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin)
    JavaCompile javaCompile = variant.javaCompile
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.5",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", android.bootClasspath.join(
                File.pathSeparator)]

        MessageHandler handler = new MessageHandler(true);
        new Main().run(args, handler)

        def log = project.logger
        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:
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break;
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break;
            }
        }
    }
}

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.+'
    testCompile 'junit:junit:4.12'
    compile 'org.aspectj:aspectjrt:1.8.1'
}
apply plugin: 'com.android.application'
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.3"
    defaultConfig {
        applicationId "com.hj.aopdemo"
        minSdkVersion 14
        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'
        }
    }
}

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.5",
                         "-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 {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    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'
    compile 'org.aspectj:aspectjrt:1.8.1'
    testCompile 'junit:junit:4.12'
    compile project(':aoplib')
}

通过如上配置,我们就完成了在Android Studio中的项目工程接入AspectJ的配置工作
这个配置有点繁琐,因此网上其实已经有人写了相应的gradle插件,具体可以参考:
AspectJ Gradle插件

2.实例代码

接下来一个实例包含如何配置,以及基本的操作,如日志输出,异常特殊处理。

@Aspect
public class ExceptionAspect {

    @Pointcut("handler(Exception)")
    public void handlerException(){}
    @Pointcut("within(*..MainActivity)")
    public void codeInActivity() {}

    @Before("codeInActivity() && handlerException()")
    public void beforeException(JoinPoint joinPoint) {
        if (joinPoint != null) {
            Signature signature =joinPoint.getSignature();
            String className = signature.getDeclaringType().getSimpleName();
            Log.d(className, "beforeException");
        }
    }
}
@Aspect
public class TraceAspect {
    private static final String POINTCUT_METHED = "execution(@com.hj.aoplib.annotation.DebugTrace * *(..))";//含DebugTrace注解的方法,任意返回值,任意名字,任意参数
    private static final String POINTCUT_CONSTRUCTOR = "execution(@com.hj.aoplib.annotation.DebugTrace *.new(..))";//含DebugTrace注解的类,构造函数,任意参数

    @Pointcut(POINTCUT_METHED)
    public void methodAnnotatedWithDebugTrace() {}
    @Pointcut(POINTCUT_CONSTRUCTOR)
    public void constructorAnnotatedWithDebugTrace() {}

    @Around("methodAnnotatedWithDebugTrace() || constructorAnnotatedWithDebugTrace()")
    public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
        if (joinPoint != null) {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            String className = methodSignature.getDeclaringType().getSimpleName();
            String methodName = methodSignature.getMethod().getName();

            Log.d(className, methodName + "weaveJoinPoint");
            final StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            Object obj = joinPoint.proceed();
            stopWatch.stop();
            //记录方法耗时并输出
            Log.d(className, buildLogMessage(methodName, stopWatch.getTotalTimeMillis()));
            return obj;
        }
        return null;
    }

    private static String buildLogMessage(String methodName, long methodDuration) {
        StringBuilder message = new StringBuilder();
        message.append("耗时 --> ");
        message.append(methodName);
        message.append(" --> ");
        message.append("[");
        message.append(methodDuration);
        message.append("ms");
        message.append("]");

        return message.toString();
    }
}
public class MainActivity extends AppCompatActivity {

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

    @DebugTrace
    public void test(View v) {
        Log.d("MainActivity", "test-weaveJoinPoint");
        try {
            Thread.sleep(100);
            throw new IllegalArgumentException("Exception");
        } catch (Exception e) {
        }
    }
}

具体源码请访问GitHub,地址如下https://github.com/hhhhskfk/aopdemo

JakeWharton/hugo(基于AspectJ实现的AOP日志记录函数库)
源码

上一篇 下一篇

猜你喜欢

热点阅读