AspectJX学习笔记

参考文档:

Introduction to AspectJ
Github: AspectjDemo
Android监测用户行为之中AOP编程之AspectJ实战 作者:weixin_33726943
Android中的AOP的实现及AspectJ的使用 作者:岩浆李的游鱼
深入理解Android之AOP 作者:阿拉神农

基本概念:

  • Join Points(连接点):简称JPoints,是AspectJ的核心思想之一,把程序的整个执行过程划分成几个关键点,包括构造方法调用,调用方法,方法执行,抛出异常等。这些关键点可以作为Join Points,将想要执行的内容插入到这些时机中。
  • Pointcuts(切入点):指定相应Advice需要插入的位置。
  • Advice(通知):指定代码将注入到Pointcuts的什么位置。
  • Aspect(切面):Pointcut和Advice组合到一起,形成了一个明确的位置,也就是切面。

一、Pointcuts切入点

用来描述 JPoint 注入点的一段表达式,比如:调用 Animal 类 fly 方法的地方,call(* Animal.fly(..))。

时机命令
函数执行(在函数内部)execution(MethodPattern)
函数调用(调用函数的位置)call(MethodPattern)
构造函数执行execution(ConstructorPattern)
构造函数调用call(ConstructorPattern)
静态初始化staticinitialization(TypePattern)
读取属性get(FieldPattern)
设定属性set(FieldPattern)
异常处理(对应catch内的执行)handler(TypePattern)
Advice执行时adviceexecution()

1、明确指定切入点

方法签名为void Point.setX(int),Point的setX方法,入参是1个int类型,返回值为void

call(void Point.setX(int))

2、使用条件运算符指定切入点

可以通过&&,||,!进行逻辑运算。

call(void Point.setX(int)) ||
call(void Point.setY(int))

3、使用通配符指定切入点

筛选出Figure类,函数名以make开头,任意参数,返回值为void的方法。

call(void Figure.make*(..))

4、限定访问权限的切入点

限定Figure类,任意函数名,任意参数,任意返回值,public方法。

call(public * Figure.* (..))

二、Advice建议

常见的有 Before、After、Around 等,表示代码执行前、执行后、替换目标代码,也就是在 Pointcut 何处注入代码。

注解用途
Before在执行JPoint之前
After在执行JPoint之后
Around替换原需要执行的代码,如果需要执行源代码,可以使用jointPoint.proceed()方法。
AfterReturning正常return时
AfterThrowing抛出异常时

三、AspectJX使用

AspectJX是沪江网开源的一个支持Android的AspectJ库。Github:gradle_plugin_android_aspectjx

1、环境配置

  • 在根目录的build.gradle增加AspectJX的依赖。
dependencies {
    classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
}
  • 修改需要使用AspectJX的模块的build.gradle。
dependencies {
    // ..
    implementation 'org.aspectj:aspectjrt:1.9.5'
    // ..
}

apply plugin: 'android-aspectjx'

aspectjx {
    //排除部分路径
    exclude 'android'
    exclude 'com.alibaba'
}

2、创建Aspect类

需要在类上注解@Aspect,函数上注解需要注入的路径

returning参数可以指明返回值。

package com.irisleon.fridge.util;

import android.util.Log;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class TrackHelper {
   private static final String TAG = "TrackHelper";

   @Before("execution(* com.irisleon.fridge.*.*.*(..)) || execution(* com.irisleon.fridge.*.*(..))")
   public void DebugFunctionLog(JoinPoint joinPoint) throws Throwable {
      Log.d(TAG, "----> FuncTrace:" + joinPoint.getSignature());
      Log.d(TAG, "        At:" + joinPoint.getSourceLocation());
      for (Object item : joinPoint.getArgs()) {
         if (item != null) {
            Log.d(TAG, "        Arg:" + item.toString());
         }
      }
   }

   @AfterReturning(pointcut = "execution(* com.irisleon.fridge.*.*.*(..)) || execution(* com.irisleon.fridge.*.*(..))",
         returning = "retVal")
   public void DebugReturnLog(JoinPoint joinPoint, Object retVal) throws Throwable {
      Log.d(TAG, "<---- FuncTrace:" + joinPoint.getSignature());
      if (retVal != null) {
         Log.d(TAG, "        Return:" + retVal);
      }
   }
}

3、效果展示

image.png

4、使用场景

1)收集用户点击事件,入参。不需要侵入式修改每一个点击事件,只需要统一监听onClick,onTouch等事件。
2)判断某个函数是否有调用权限。例如@Around注解。判断用户是否已经登录。如果未登录,或者没有权限,则不继续进行处理。如果可以继续操作,调用jointPoint.proceed()。


GiraKoo
0 声望0 粉丝

Practice makes perfect.