项目实训(十八)借助aspectj实现AOP编程初探

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhang___yong/article/details/81948197

1.首先要知道一点自定义注解:

用来标识注解的注解称为元注解,一共四种:Target指定注解的对象(类,方法,属性),Retention指定注解的生命周期(SOURCE,CLASS,RUNTIME)依次递增,RUNTIME表示保留到运行时。Inherited表示可以被子类继承,Documented表示注解信息添加到java文件中。

更新一下Rentention的理解:SOURCE在编译成class文件的时候被丢弃,一般用于@Override等检查注解。CLASS在jvm加载class时被丢弃,可用于butterknife等在编译期生成代码的。RUNTIME则一直保留到运行时,用于需要在运行时动态获取信息的。

新建一个Annotation文件(或者java文件改class为@interface),注解中有属性的概念,如定义一个属性:

int a() default 1;

default 1顾名思义就是默认值,可以不写。加上生命周期和修饰对象后:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int a() default 1;
}

找个方法试一试:

    @MyAnnotation(a = 2)
    public void test(){

    }

2.aspectj是在java编译成class字节码的时候向注解处插入一些代码从而实现功能的。AOP指面向切面编程,统一处理项目中的一类问题,例如一种常见的情况,用户登录。很多界面要求先登录才能进入,这里就产生了一个登录判断的需求,可以对这些需求一一写重复的代码判断,也可以使用AOP的思想,在这些地方使用一个注解,注解定义了判断等操作,这样显得简洁明了。

开始操作:

1.导入aspectj:

在libs中加入aspectj的jar包,然后在项目的gradle里配置(提示下载失败,重启就可以了。。。):

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.8'
        classpath 'org.aspectj:aspectjweaver:1.8.8'
    }
}

在app.gradle末尾加上这些代码(运行aspectj,打印Log等操作):

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
//标注1
final def log = project.logger
final def variants = project.android.applicationVariants

variants.all { variant ->
    //标注2
    if (!variant.buildType.isDebuggable()) {
        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return;
    }
    //标注3
    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);
        //标注4
        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;
            }
        }
    }
}

2.新建一个aspectj注解类:

@Aspect
public class MyAspectj {

    @Pointcut("execution(@com.example.zhangyong.myapplication.MyAnnotation * *(..))")
    public void process(){
        Log.v("zy","process");
    }

    @Around("process()")
    public void beforeProcess(JoinPoint point){
        Log.v("zy","beforeProcess");
    }
}

@Pointcut表示切入点,也就是要插入代码的对象,这里execution里的路径表示被MyAnnotation修饰的方法,注意这里使用了通配符,里面的()表示方法的参数。

@Around表示插入代码的位置,括号里指定上面定义的那个方法,与之对应的还有@Before,@After。假设修饰的方法叫test,则实际运行时代码执行顺序:Before--test。test--After。而Around只会执行这个@Around修饰的方法,不会执行test,可以在方法内通过参数JoinPoint point来手动执行。

参数不一定是JoinPoint,也可以是ProceedingJointPoint。ProceedingJointPoint可以直接调用proceed执行。JoinPoint定义参考https://www.jianshu.com/p/27b997677149

3.一个从JoinPoint获取信息的例子:

    @Before("process()")
    public void beforeProcess(ProceedingJoinPoint point){
        //获取签名
        Signature signature = point.getSignature();
        if (!(signature instanceof MethodSignature)){
            //判断修饰的是方法
            throw new IllegalStateException("只能修饰方法");
        }
        MethodSignature methodSignature = (MethodSignature) signature;
        MyAnnotation annotation =         
              methodSignature.getMethod().getAnnotation(MyAnnotation.class);
        int a = annotation.a();
        try {
            //还有一个有参数的重载,方法执行所需的参数都需要传的
            point.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

刚才又看到一个例子,可以指定Pointut为所有onCreate等方法来打印生命周期

猜你喜欢

转载自blog.csdn.net/zhang___yong/article/details/81948197