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()。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。