文章目录
简介
AOP是Aspect Oriented Programming的简称,面向切面编程,能够在不侵入代码的前提下针对同一类问题进行统一处理,使用场景主要包括日志记录、性能统计、安全控制、事务处理、异常处理等。
其实说白了就是在程序编译到执行的某个阶段以正常编码以外的方式实现一些特殊的需求,这些需求包括方便开发(Databinding、EventBus等)、统一处理(某些方法执行前需要判断是否登录)、统计信息(哪些功能用户感兴趣、方法执行时间)等。
实现AOP的方式主要有5种:
- APT:注解处理器,编译阶段使用,可以生成java文件,比如Databinding和Arouter等框架都是通过注解生成java文件来方便开发。
- AspectJ:一个代码生成框架,有它自己的语法规则,使用专门的编译器来生成符合JVM规范的Class字节码文件。
- ASM:Java字节码操作框架,在程序被javac编译成Class文件后去修改这个字节码文件。
- Javassist:也是Java字节码操作框架,相较于ASM,它更易编写但是性能差。
- 动态代理:一种设计模式,运行期间使用,为其他对象提供一种代理以控制对这个对象的访问,在不改动目标对象的基础上,增加其他额外的功能。
本文主要使用AspectJ。
简单使用
- 环境配置
项目的gradle中添加:
buildscript {
dependencies {
classpath "com.android.tools.build:gradle:3.5.2"
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
}
}
使用Aspectj的module中添加:
apply plugin: 'android-aspectjx'
defaultConfig {
configurations.all {
resolutionStrategy.eachDependency {
DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == "androidx.appcompat") {
if (!requested.name.startsWith("multidex")) {
details.useVersion "1.+"
}
}
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
implementation 'org.aspectj:aspectjrt:1.9.6'
- 编写代码
@Aspect
public class PerformanceAop {
private static final String LOG_TAG = PerformanceAop.class.getSimpleName();
@Around("call(* com.dean.performance.MainActivity.**(..))")
public void getMethodTime(ProceedingJoinPoint joinPoint){
long time = System.currentTimeMillis();
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
Log.d(LOG_TAG, "Method " + joinPoint.getSignature().toShortString() + " time is " + (System.currentTimeMillis() - time));
}
}
- 运行结果
PerformanceAop: Method MainActivity.setContentView(..) time is 49
选择织入位置
既然是要在原有的代码中织入代码,则首先需要确定在哪个类的哪些方法中织入代码,寻找格式如下:
<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?
类似于正则表达式的写法,其中"?"表示可选,也就是修饰符和异常可以不写,在上面的例子中使用的是
* com.dean.performance.MainActivity.**(..)
* 表示返回类型为任意类型
com.dean.performance.MainActivity.** 表示MainActivity下的所有方法
(..) 表示参数是任意参数
public * *(..) throws !*..*Math*
这个表达式表示所有抛出异常名字中没有Math的public方法
更多表达式用法见