美文网首页注解JAVA
AspectJ+AOP+注解实现用户行为统计

AspectJ+AOP+注解实现用户行为统计

作者: Chenyangqi | 来源:发表于2019-10-01 00:15 被阅读0次

本文Demo地址:https://github.com/DaLeiGe/AndroidSamples/tree/master/AspectJAOP

AspectJ概念

AspectJ 是使用最为广泛的 AOP 实现方案
适用于 Java 平台
官网地址:http://www.eclipse.org/aspectj/
AspectJ 是在静态织入代码,即在编译期注入代码的
结合自定义注解实现AOP切面实现用户行为统计

AspectJ使用

只需要关注两个点

  • 1:切入点,本案例切入点为自定义注解
  • 2:针对切入点的切入行为
举个栗子

要实现统计某个方法的执行次数,在不更改且不增加原有代码逻辑的前提下通过AspectJ和自定义注解的方式实现

AspectJ环境配置

Project glide

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

buildscript {
    repositories {
        google()
        jcenter()
        
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'

        // 版本界限:As-3.0.1 + gradle4.4-all (需要配置r17的NDK环境)
        // 或者:As-3.2.1 + gradle4.6-all (正常使用,无警告)
        classpath 'org.aspectj:aspectjtools:1.8.9'
        classpath 'org.aspectj:aspectjweaver:1.8.9'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Module glide

apply plugin: 'com.android.application'

// 版本界限:As-3.0.1 + gradle4.4-all (需要配置r17的NDK环境)
// 或者:As-3.2.1 + gradle4.6-all (正常使用,无警告)
buildscript { // 编译时用Aspect专门的编译器,不再使用传统的javac
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.9'
        classpath 'org.aspectj:aspectjweaver:1.8.9'
    }
}

android {
    compileSdkVersion 28
    buildToolsVersion "29.0.0"
    defaultConfig {
        applicationId "com.cyq.aspectjaop"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    testImplementation 'junit:junit:4.12'
    implementation 'org.aspectj:aspectjrt:1.8.13'
}


// 版本界限:As-3.0.1 + gradle4.4-all (需要配置r17的NDK环境)
// 或者:As-3.2.1 + gradle4.6-all (正常使用,无警告)
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;
            }
        }
    }
}

自定义注解ClickBehavior,作用在方法之上

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 用户点击痕迹(行为统计)  IoC容器
@Target(ElementType.METHOD) // 目标作用在方法之上
@Retention(RetentionPolicy.RUNTIME)
public @interface ClickBehavior {
    String value();
}

在要监听的业务方法上添加注解

// 用户行为统计
    @ClickBehavior("测试参数")
    public void coupon(View view) {
        Log.e(TAG, "开始跳转到 -> 我的优惠券 Activity");
        startActivity(new Intent(this, OtherActivity.class));
    }

然后就可以使用AspectJ定义切面类ClickBehaviorAspect
这个类有两个功能

  • 1:定位注解的位置(切入点)
  • 2:对切入点如何处理
import com.cyq.aspectjaop.annotation.ClickBehavior;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

@Aspect // 定义切面类
public class ClickBehaviorAspect {

    private final static String TAG = "netease >>> ";

    // 1、应用中用到了哪些注解,放到当前的切入点进行处理(找到需要处理的切入点)
    // execution,以方法执行时作为切点,触发Aspect类
    // * *(..)) 可以处理ClickBehavior这个类所有的方法
    @Pointcut("execution(@com.cyq.aspectjaop.annotation.ClickBehavior * *(..))")
    public void methodPointCut() {}

    // 2、对切入点如何处理
    @Around("methodPointCut()")
    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();

        // 统计方法的执行时间、统计用户点击某功能行为。(存储到本地,每过x天上传到服务器)
        long begin = System.currentTimeMillis();
        Log.e(TAG, "ClickBehavior Method Start >>> ");
        Object result = joinPoint.proceed(); // MainActivity中切面的方法
        long duration = System.currentTimeMillis() - begin;
        Log.e(TAG, "ClickBehavior Method End >>> ");
        Log.e(TAG, String.format("统计了:%s功能,在%s类的%s方法,用时%d ms",
                funName, className, methodName, duration));
        return result;
    }
}

执行结果如下

2019-10-01 00:13:55.263 10479-10479/com.cyq.aspectjaop E/netease >>>: ClickBehavior Method Start >>> 
2019-10-01 00:13:55.263 10479-10479/com.cyq.aspectjaop E/netease >>>: 模拟接口请求……验证通过,登录成功!
2019-10-01 00:13:55.263 10479-10479/com.cyq.aspectjaop E/netease >>>: ClickBehavior Method End >>> 
2019-10-01 00:13:55.264 10479-10479/com.cyq.aspectjaop E/netease >>>: 统计了:登录功能,在MainActivity类的login方法,用时0 ms

通过如上方式实现用户行为统计,可以避免更改原有业务逻辑

相关文章

  • AspectJ+AOP+注解实现用户行为统计

    本文Demo地址:https://github.com/DaLeiGe/AndroidSamples/tree/m...

  • 用户统计实现

    IOS用户统计实现 用户统计 用户行为统计(User Behavior Statistics, UBS)一直是移动...

  • springboot系列——自定义注解

    项目需要实现对登录用户的实时监控,对用户部分相关操作进行埋点统计。这里我使用了自定义注解,对需要监控的接口使用注解...

  • 百分点调用接口设计

    用户行为分析需求 分类回调方法 描述 用户操作行为统计统一入口 方法参数 说明:此方法为针对百分点统计用户操作行为...

  • #读书笔记#增长黑客DAY4-王悦怡

    摘要: 统计分析( Trends )和用户分组( Cohorts ):统计分组是以用户行为为中心,让数据说话。用户...

  • 神策数据-用户行为分析

    什么是用户行为分析用户行为分析,通俗的讲就是要关注用户在产品上的行为,并对用户行为进行统计和分析。 行为分析三步骤...

  • 【原】iOS动态性(三) Method Swizzling以及A

    声明:本文是本人编程小翁原创,转载请注明。 用户统计.jpeg 用户行为统计(User Behavior Stat...

  • Redis高级功能之 - bitmap

    亿级活跃用户场景 实现日活跃统计 实现周活跃统计 为了增强用户粘性,增加一个连续打卡发放积分功能,怎么实现连续打卡...

  • java基础类-5-注解

    概述 注解:元数据注解本身仅仅是元数据,和业务逻辑无关,业务逻辑是注解的用户来实现的,比如JVM也是这样的一个用户...

  • 用户行为流程分析法及在金融分析中的应用

    一、用户行为路径分析 1. 什么是用户行为路径分析? 用户行为路径分析是一种监测用户流向,从而统计产品使用深度的分...

网友评论

    本文标题:AspectJ+AOP+注解实现用户行为统计

    本文链接:https://www.haomeiwen.com/subject/eezhpctx.html