android aop(三) AspectJ

AspectJ是面向切面编程的一个框架,它遵循了Jvm的语法并扩展了java语言,我们知道一个类想要运行起来,是先javac命令变成.class(字节码) 再由java命令把该类加载到jvm中,而AspectJ就在javac命令在.java 文件转变成.class文件的时候植入一些代码,这是在编译期完成的,不会影响性能

 

但是在使用AspectJ有一些炕,比如:

android  studio  3.0.1   gradle-all 4.4要配置一个ndk r17

这要去下载ndk-r17的环境然后配置好

android  studio  3.2.1   gradle-all 4.6这是最好的

android  studio  3.4.0   gradle-all 5.1.1有过时的api警告

下面讲下aspectJ在Android中的配置

第一步

在根目录的build.gradle中配置如下:

 classpath 'org.aspectj:aspectjtools:1.8.9'
 classpath 'org.aspectj:aspectjweaver:1.8.9'

第二步

在项目的build.gradle配置

配置一:

buildscript { // 编译时用Aspect专门的编译器,不再使用传统的javac
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.9'
        classpath 'org.aspectj:aspectjweaver:1.8.9'
    }
}

如图:

配置2

在dependencies中引入依赖库

implementation 'org.aspectj:aspectjrt:1.8.13'

当你引入这个库后再编译就发现报错了:

上面的问题暂是不解决  把gradle 改成4.6 studio改成3.2.1 错误最后去解决 然后还要配置在

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

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

这个配置跟android和dependencies是同级  别配置错了  这是groovy的语法

上面环境全部配置好了,现在使用AspectJ

第一个案例

统计某个方法执行的时间

先定义一个注解

@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME)
public @interface ClickBehavior {
    String value();
}

再定义一个切面类

@Aspect // 定义切面类
public class ClickBehaviorAspect {
    private final static String TAG = ClickBehaviorAspect.class.getSimpleName();
    @Pointcut("execution(@com.example.login.annotation.ClickBehavior * *(..))")
    public void pointCut() {}

    // 2、对切入点如何处理
    @Around("pointCut()")
    public Object jointPotin(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取签名方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取方法所属的类名
        String className = methodSignature.getDeclaringType().getSimpleName();
        // 获取方法名
        String methodName = methodSignature.getName();
        // 获取方法的注解值(需要统计的用户行为)
        String funName = methodSignature.getMethod().getAnnotation(ClickBehavior.class).value();
        long begin = System.currentTimeMillis();
        Object result = joinPoint.proceed(); // MainActivity中切面的方法
        long duration = System.currentTimeMillis() - begin;
        Log.e(TAG, "此方法运行的时长:"+duration);
        return result;
    }
}

使用:

  @ClickBehavior("收藏")
    private void collect() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.e("ClickBehaviorAspect","收藏");
    }

其实AspectJ实现起来还是挺简单的,现在对上面的代码进行说明

Pointcut:切入点,它后面跟随的是表达式,比如execution是固定写法,后面
@com.netease.aop.login.annotation.ClickBehavior  * *(..)

是指那个方法中使用到了该ClickBehavior注解,pointCut()方法是随便定义的,不需要具体实现

@Around("pointCut()")是对切点进行处理,@Around括号中的切入点标记要和上面定义的保持一致,

Around:表示在对切入点前后都可以进行一些额外的操作,就是说在你使用到的那个注解方法前后可以进行一些业务操作

Before:表示在对切入点前可以进行一些额外的操作,就是说在你使用到的那个注解方法前可以进行一些业务操作

After:表示在对切入点后可以进行一些额外的操作,就是说在你使用到的那个注解方法后可以进行一些业务操作

 

当然如果要很了解AspectJ中一些通配符的使用,就去查下,如果是Java后端的哥们,学过Spring的现在是必会.

AOP背后的原理还是使用了动态代理.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值