前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android--AOP架构设计之使用AspectJ监测方法耗时

Android--AOP架构设计之使用AspectJ监测方法耗时

作者头像
aruba
发布2021-12-06 17:38:00
9880
发布2021-12-06 17:38:00
举报
文章被收录于专栏:android技术
AOP为面向切面编程,听着很高大上,实际上就是为了将业务分离,比如我们在网络请求时,需要生成一个签名放入请求头Header,以往的做法是封装一个方法获取签名,AOP只是实现方式不同,将封装方法改为注解形式
AOP概念,将注解的方法、对象等看成是一个点,由这些被注解的点构成一个面,然后对这个面做具体的处理。这就是三个步骤而已,没什么高端的
AOP也有很多实现方式,AspectJ是利用替换Javac编译器方式,将字节码改变,来达到调用我们注解方法
一、AspectJ注解

使用AspectJ,需要用到它提供的注解:

  • Aspect:Aspect 注解类,来表明该类使用AOP进行编程,相当于编译器进行字节码改变的入口
  • Pointcut:表示一个面,可以通过通配、正则表达式等指定,使用这些点来构成该面

还有就是最后一步,具体处理方法使用的注解:

  • Before:表示在调用点之前,调用该方法
  • After:表示在调用点之后,再调用该方法
  • Around:使用该方法代替该点的执行
二、Gradle配置

AspectJ是一个客户端,拥有自己的编译器,所以要在Gradle中指定,使用AspectJ的编译器进行编译

1.在module的gradle最上面添加:
代码语言:javascript
复制
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.9.6'
        classpath 'org.aspectj:aspectjweaver:1.9.6'
    }
}

plugins {
    id 'com.android.application'
}

...
2.上面的gradle中新增编译脚本
代码语言:javascript
复制
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;
            }
        }
    }
}
3.依赖库文件

下载地址:https://gitee.com/aruba/aopapplication/blob/master/app/libs/aspectjrt.jar

完整gradle代码如下:
代码语言:javascript
复制
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.9.6'
        classpath 'org.aspectj:aspectjweaver:1.9.6'
    }
}

plugins {
    id 'com.android.application'
}

android {
    compileSdk 30

    defaultConfig {
        applicationId "com.aruba.aopapplication"
        minSdk 21
        targetSdk 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}


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

dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation files('libs\\aspectjrt.jar')
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
三、使用
1.定义注解,来用于表示一个点
代码语言:javascript
复制
/**
 * 用于注解点
 * Created by aruba on 2021/11/1.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BehaviorTrace {
    String value();
}
2.使用Aspect

首先使用Aspect注解类,再通过Pointcut注解指定该切面中的点(这边就是方法),最后使用Around注解来替换原来的方法执行

代码语言:javascript
复制
/**
 * Created by aruba on 2021/11/1.
 */
@Aspect
public class AspectBehavior {

    //指定使用BehaviorTrace注解的所有包下所有类的所有方法,为一个切面
    @Pointcut("execution(@com.aruba.aopapplication.annotations.BehaviorTrace * *(..))")
    public void methodAnnotatedWithBehaviorTrace() {
    }

    //争对上面切面methodAnnotatedWithBehaviorTrace的所有点进行处理
    @Around("methodAnnotatedWithBehaviorTrace()")
    public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) {
        Object ret = null;

        try {
            //获取方法签名
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            //获取注解
            BehaviorTrace annotation = methodSignature.getMethod().getAnnotation(BehaviorTrace.class);

            //执行之前记录下时间
            long startTime = System.currentTimeMillis();
            //方法执行
            ret = joinPoint.proceed();
            //方法执行完后的耗时
            long diffTime = System.currentTimeMillis() - startTime;

            String clzName = methodSignature.getDeclaringType().getSimpleName();
            String methodName = methodSignature.getName();

            Log.d("aruba", String.format("功能:%s 类:%s中方法:%s执行耗时:%d ms", annotation.value(), clzName, methodName, diffTime));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        return ret;
    }

}
3.使用自定义注解来注解方法

注解方法就是表示该方法为一个点

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {

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

    @BehaviorTrace("上传")
    public void upload(View view) {
        SystemClock.sleep(300);
    }

    @BehaviorTrace("下载")
    public void download(View view) {
        SystemClock.sleep(400);
    }

    @BehaviorTrace("扫码")
    public void scan(View view) {
        SystemClock.sleep(500);
    }
}

三个按钮点击后的日志如下:

项目地址:https://gitee.com/aruba/aopapplication/tree/master
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/11/1 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • AOP为面向切面编程,听着很高大上,实际上就是为了将业务分离,比如我们在网络请求时,需要生成一个签名放入请求头Header,以往的做法是封装一个方法获取签名,AOP只是实现方式不同,将封装方法改为注解形式
  • AOP概念,将注解的方法、对象等看成是一个点,由这些被注解的点构成一个面,然后对这个面做具体的处理。这就是三个步骤而已,没什么高端的
  • AOP也有很多实现方式,AspectJ是利用替换Javac编译器方式,将字节码改变,来达到调用我们注解方法
  • 一、AspectJ注解
  • 二、Gradle配置
    • 1.在module的gradle最上面添加:
      • 2.上面的gradle中新增编译脚本
        • 3.依赖库文件
          • 完整gradle代码如下:
          • 三、使用
            • 1.定义注解,来用于表示一个点
              • 2.使用Aspect
                • 3.使用自定义注解来注解方法
                  • 项目地址:https://gitee.com/aruba/aopapplication/tree/master
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档