Android AOP面向切面设计编程

2,846 阅读3分钟

AOP介绍

AOP为Aspect Oriented Programming的缩写,即面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点。

作用

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的 耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP基础

要了解AOP,首先需要AOP的基础,也就是其关键点:切点、切面、连接点等等

通知:注入到class文件中的代码。

连接点:程序中可能作为代码注入目标的特定的点,例如一个方法调用或者方法入口。

切入点:告诉代码注入工具,在何处注入一段特定代码的表达式

切面:Pointcut 和 Advice 的组合看做切面。

织入: 注入代码(advices)到目标位置(joint points)的过程。

AOP在Android的应用

在Android中已经有一些库和工具帮助我们简单的使用AOP编程的了,如ASMDEX、AspectJ、DexMaker、Javassist for Android等等,这些库各有自己的优缺点,详情可以参考《Android AOP 总结》 这篇文章,该文章总结得比较详细。

既然使用了AOP,必有它的用处,具体在Android中哪里可以使用AOP编程呢? 一般的我们可以使用AOP实现一下这些功能,并且可以做好封装,方便我们开发人员使用:

1)日志

2)性能监控

3)数据校验

4)统计

5)权限验证

当然除了以上的使用之外,可以更多的地方可能需要用到AOP编程。

了解了这么多的AOP知识,接下来带大家使用AspectJ,在Android中实现AOP编程。

AspectJ

为什么使用AspectJ呢?主要是AspectJ功能比较强大,易于使用,注解也比较多和支持编译时注入方式。既然选择了,那么接下来就看下如何使用AspectJ。

1)下载jar包,使用AspectJ必须到官网下载它的jar,地址:

http://www.eclipse.org/aspectj/downloads.php

2)将jar放到项目的libs下,同时Add As Library

AspectJ

AspectJ

3)在app的build.gradle的配置,需要加入一下代码

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'
    }
}

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;
            }
        }
    }
}

4)创建注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface AOPTrace {
    String getValue();
}

ElementType.METHOD表明用在方法上,RetentionPolicy.CLASS表示这个注解周期声明在 class 文件上。

5)创建Aspect类

@Aspect
public class AOPAspect {


    /**
     * 切点
     */
    @Pointcut("execution(@com.main.aop.AOPTrace  * *(..))")
    public void annoAOP() {

    }

    /**
     * 切面
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("annoAOP()")
    public Object dealPoint(ProceedingJoinPoint point) throws Throwable {
        //方法执行前
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        AOPTrace behaviorTrace = methodSignature.getMethod().getAnnotation(AOPTrace.class);
        String value = behaviorTrace.getValue();
        Log.i("test",""+value);
        //方法执行时
        Object object = null;
        try {
            object = point.proceed();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return object;
    }
    
}

@Pointcut声明注解的方法,也就是切点,object = point.proceed();执行注解的方法,需要把object返回即可。

6)使用

public class AopActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_aop);
        this.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                test();
            }
        });
    }

    /**
     * aop
     */
    @AOPTrace(getValue = "aop")
    private void test()
    {
        Log.i("test","你好,我是aop");
    }
}

使用的时候,直接在使用方法哪里,添加刚刚我们创建的注解即可

@AOPTrace(getValue = "aop")

7)运行结果

AspectJ

结果表示已经成功实现AOP编程了,使用这种方式可以很方便实现包括日志输入,权限验证和统计等功能。

参考文章:《【翻译】Android中的AOP编程》,地址:

https://www.jianshu.com/p/0fa8073fd144

参考AspectJ的写法

https://fernandocejas.com/2014/08/03/aspect-oriented-programming-in-android/