概述
AspectJ是一种编译器,它在Java编译器的基础上增加了关键字识别和编译方法。因此,AspectJ可以编译Java代码,它还提供了Aspect程序,在编译期间,将开发者编写的Aspect程序加入到目标程序中,扩展目标程序的功能。
使用AspectJ有两种方法:
- 使用AspectJ语言,这种语言和Java几乎一样,也能在AspectJ中调用Java的任何类库,AspectJ只是多了一些关键词
- 使用Java语言开发,然后使用@AspectJ注解
在Android平台,常用的是沪江的aspectjx,该框架基于Android Gradle Transform。
Join Points
Join Points可以看作是程序运行时的一个执行点,比如函数的调用,执行等。
Join Points | 说明 | 示例 |
---|---|---|
method call | 函数调用 | 比如调用Log.e() |
method execution | 函数执行 | 比如Log.e()的执行内部 |
constructor call | 构造函数调用 | 和method call类似 |
constructor execution | 构造函数执行 | 和method execution类似 |
field get | 获取某个变量 | |
field set | 设置某个变量 | |
pre-initialization | Object在构造函数前做的一些工作 | |
initialization | Object在构造函数中做的工作 | |
static initialization | 类初始化 | 比如类的static{} |
handler | 异常处理 | 比如try catch()中,对应catch内的执行 |
某些AspectJ框架中不是所有AspectJ支持的JPoint都有。
Pointcuts
切入点可以通过在一个方法上使用@Pointcut来指定,这个方法必须返回void,方法的参数与切入点的参数一致,方法的修饰符与切入点的修饰符一致。
一般情况下,使用@Pointcut注解的方法的方法体必须是空的,并且没有任何throws语句。如果切入点绑定了形式参数(使用args()、target()、this()、@args()、@target()、@this()、@annotation()),那么它们必须也是方法的形式参数。
1 |
|
- call:处理Join Point的类型,例如call、execution
- 第一个
*
表示返回值,*表示返回值为任意类型 - 第二个
*.*
是匹配方法,*
是进行通配,几个*
没区别 android.app.Activity.on**
表示on开头的方法- 可以通过
&&
、||
、!
来进行条件组合 ()
代表方法参数,可以指定类型,例如android.os.Bundle,或者(..)
这样来代表任意类型、任意个数的参数
Advice
Before、After、AfterReturning、AfterThrowing或者Around(等效于Before和After)等。
Java原生AspectJ
安装:
- 下载AspectJ:AspectJ
- 运行:
java -jar /Users/guangjie.peng/development/aspectj-xxx.jar
- 将bin目录添加到环境变量,将lib目录下的jar添加到CLASSPATH
Main.java:
1 | public class Main { |
MyAspect.java:
1 | public aspect MyAspect { |
运行:
1 | ajc -d *.java |
Android平台AspectJ
根gradle脚本:
1 | classpath 'com.android.tools.build:gradle:3.6.3' |
子module:
1 | apply plugin: 'android-aspectjx' |
Service:
1 | public class Service { |
Aspect:
1 |
|
自定义Pointcuts
注解类:
1 |
|
Aspect:
1 |
|
添加注解:
1 | public class Service { |