1. 什么是 AOP (Aspect Oriented Programming)
1.1 Why AOP ?
我们都知道 OOP(Object-Oriented Programming) 是面向对象编程思想,即在 OOP
的世界里万物皆对象,将数据和数据的行为放到一起,成为一个不可分割的整体 – 对象,其精髓是将功能或问题模块化,每个模块管理自己的业务,使我们在使用时不用关心它的内部细节和实现过程。
但是这样的设计在某些情况下并不能很好的处理问题,举个例子,在 Android
的日常开发中对相应对象进行Log
日志的打印,我们一个功能模块 A
添加这样一个日志打印功能,具体实现只能是在项目调用模块 A
时手动添加打印 Log
日志代码。虽然这样也能满足相应的功能需要,但是需要每次都调用相同的代码,显然,这样的处理方式不是最优的。这时利用 AOP
思想便能很好的处理这个功能需要。
1.2 What’s AOP ?
AOP (Aspect Oriented Programming) – 面向切面编程思想,它提倡的是针对同一类问题或功能的统一处理,此处同一类问题即为一个切面,程序中只要有这个功能都会作出相同的反应(自己浅薄的认识)
1.3 OOP VS AOP
AOP
、OOP
在字面上虽然非常类似,却是面向不同领域的两种设计思想。OOP(面向对象编程)
针对业务处理过程的实体及其属性和行为进行抽象封装
,以获得更加清晰高效的逻辑单元划分。
而 AOP
则是针对业务处理过程中的切面进行提取
,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。
1.4 AOP 方案有哪些 ?
AspectJ: 一个 JavaTM 语言的面向切面编程的无缝扩展(适用Android)。
Javassist for Android: 用于字节码操作的知名 java 类库 Javassist 的 Android 平台移植版。
DexMaker: Dalvik 虚拟机上,在编译期或者运行时生成代码的 Java API。
ASMDEX: 一个类似 ASM 的字节码操作库,运行在Android平台,操作Dex字节码。
1.5 Why AspectJ
- 功能强大
- 支持编译期和加载时代码注入
- 易于使用
2. 在 Android 项目中使用 AspectJ
2.1 What’s AspenctJ
AspectJ
实际上是对 AOP
编程思想的一个实践,它不是一个新的语言,它就是一个代码编译器(ajc),在Java 编译器
的基础上增加了一些它自己的关键字识别和编译方法。因此,ajc
也可以编译 Java
代码。它在编译期将开发者编写的 Aspect
程序 Wave (编织)
到目标程序中,对目标程序作了重构,目的就是建立目标程序与 Aspect
程序的连接(耦合,获得对方的引用(获得的是声明类型,不是运行时类型)和上下文信息),从而达到 AOP
的目的(这里在编译期还是修改了原来程序的代码,但是是 ajc
替我们做的)。
2.2 集成 AspectJ
- 插件的方式:具体使用方法见 gradle-android-plugin-aspectjx
- Gradle 配置的方式 :具体见 Aspect Oriented Programming in Android 中 Making AspectJ to work with Android 的对项目的配置。
import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.12.+'
classpath 'org.aspectj:aspectjtools:1.8.1'
}
}
apply plugin: 'android-library'
repositories {
mavenCentral()
}
dependencies {
compile 'org.aspectj:aspectjrt:1.8.1'
}
android {
compileSdkVersion 19
buildToolsVersion '19.1.0'
lintOptions {
abortOnError false
}
}
android.libraryVariants.all { variant ->
LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin)
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.5",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", plugin.project.android.bootClasspath.join(
File.pathSeparator)]
MessageHandler handler = new MessageHandler(true);
new Main().run(args, handler)
def log = project.logger
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break;
case IMessage.WARNING:
case IMessage.INFO:
log.info message.message, message.thrown
break;
case IMessage.DEBUG:
log.debug message.message, message.thrown
break;
}
}
}
}
参考资料
深入理解Android之AOP
看AspectJ在Android中的强势插入
Aspect Oriented Programming in Android
Android中的AOP编程之AspectJ实战实现数据埋点