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、成果展现
4、应用场景
1)收集用户点击事件,入参。不须要侵入式批改每一个点击事件,只须要对立监听 onClick,onTouch 等事件。
2)判断某个函数是否有调用权限。例如 @Around 注解。判断用户是否曾经登录。如果未登录,或者没有权限,则不持续进行解决。如果能够持续操作,调用 jointPoint.proceed()。