AOP之AspectJ - 代码注入
一、AOP简介
1.1 什么是AOP编程
AOP是Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP编程是一种区别OOP编程的概念,从切面的角度看待问题,是函数式编程的一种衍生范型。在AOP中,我们不需要显式的修改就可以向代码中添加可执行的代码块,有效的保证了业务逻辑的各个部分的隔离,降低耦合度,提高程序的可重用性,同时提高了开发的效率。
OOP的思想让我们把功能或问题模块化,每个模块有自己的职责和使命。相比较,AOP让我们在保持开发模块隔离的同时可以将一些需要横跨多个模块的代码嵌入其中,把涉及到众多模块的某一类问题进行统一管理。
1.2 使用场景
- 性能监控: 在方法调用前后记录调用时间,方法执行太长或超时报警。
- 无痕埋点: 在需要埋点的地方添加对应统计代码。
- 缓存代理: 缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。
- 记录日志: 在方法执行前后记录系统日志。
- 权限验证: 方法执行前验证是否有权限执行当前方法,没有则抛出没有权限执行异常,由业务代码捕捉。
- 其它
1.3 工具和库
目前已有不少的工具和库能帮助我们方便使用AOP。
- AspectJ: 一个 JavaTM 语言的面向切面编程的无缝扩展(适用Android)。
- 简介:可以织入所有类;支持编译期和加载时代码注入;编写简单,功能强大。需要使用ajc编译器编译,ajc编译器是java编译器的扩展,具有其所有功能。
- Javassist for Android: 用于字节码操作的知名 java 类库 Javassist 的 Android 平台移植版。
- 简介:可以织入绝大部分类;运行时生成,减少不必要的生成开销;通过将切面逻辑写入字节码,减少了生成子类的开销,不会产生过多子类。运行时加入切面逻辑,产生性能开销。
- DexMaker: Dalvik 虚拟机上,在编译期或者运行时生成代码的 Java API。
- 简介:支持编译期和加载时代码注入;运行在Android Dalvik VM上,利用Java编写,来动态生成DEX字节码的API。
- ASMDEX: 一个类似 ASM 的字节码操作库,运行在Android平台,操作Dex字节码。
- 简介:可以织入所有类;支持编译期和加载时代码注入。修改字节码,需要对class文件比较熟悉,编写过程复杂。
二、AspectJ
2.1 简介
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件,支持静态编译和动态编译。
- 优点:可以织入所有类;支持编译期和加载时代码注入;编写简单,功能强大。
- 缺点:需要使用ajc编译器编译,ajc编译器是java编译器的扩展,具有其所有功能。
使用AspectJ编码更为简洁,API简单易用。个人觉得,在Android开发中,是实现AOP的首选。
2.2 一些专业术语
- Cross-cutting concerns(横切关注点): 尽管面向对象模型中大多数类会实现单一特定的功能,但通常也会开放一些通用的附属功能给其他类。例如,我们希望在数据访问层中的类中添加日志,同时也希望当UI层中一个线程进入或者退出调用一个方法时添加日志。尽管每个类都有一个区别于其他类的主要功能,但在代码里,仍然经常需要添加一些相同的附属功能。
- Advice(通知): 注入到class文件中的代码。典型的 Advice 类型有 before、after 和 around,分别表示在目标方法执行之前、执行后和完全替代目标方法执行的代码。 除了在方法中注入代码,也可能会对代码做其他修改,比如在一个class中增加字段或者接口。
- Joint point(连接点): 程序中可能作为代码注入目标的特定的点,例如一个方法调用或者方法入口。
- Pointcut(切入点): 告诉代码注入工具,在何处注入一段特定代码的表达式。例如,在哪些 joint points 应用一个特定的 Advice。切入点可以选择唯一一个,比如执行某一个方法,也可以有多个选择,比如,标记了一个定义成@DebguTrace 的自定义注解的所有方法。
- Aspect(切面): Pointcut 和 Advice 的组合看做切面。例如,我们在应用中通过定义一个 pointcut 和给定恰当的advice,添加一个日志切面。
- Weaving(织入): 注入代码(advices)到目标位置(joint points)的过程。
下面引用《Aspect Oriented Programming in Android》中的两张图来帮助我们更好地理解这些概念:
图1:
图2:
2.3 基础知识
继续向下阅读之前,你可能需要先了解一些基础知识以便更好地理解。由于篇幅有限,无法扩展详解,可以根据以下列出的内容先行了解。
往后的内容我们将针对AspectJ的具体使用和如何根据使用场景做成插件来展开探讨。
2.4 AspectJ使用配置
(Android Studio Gradle)
1.添加 dependencies classpath
classpath 'org.aspectj:aspectjtools:1.8.10'
2.添加 dependencies compile
compile 'org.aspectj:aspectjrt:1.8.10'
3.build.gradle添加task命令
(若为多Module则每个Module对应的gradle都需添加)
import org.aspectj.bridge.IMessage
import org.aspectj.