Android 编译期的黑科技(二)- AOP 篇
AOP 定义
AOP 是 Aspect Oriented Programming 的缩写,即“面向切面编程”。使用 AOP,可以在编译期间对代码进行动态管理, 以达到统一维护的目的。AOP 是 OOP 编程的一种延续,也是 Spring 框架中的一个重要模块。利用 AOP 可以对业务逻辑 的各个模块进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高开发的效率。利用 AOP,我们可以在无浸入的在宿主中插入一些代码逻辑,从而可以实现一些特殊的功能,比如日志埋点、性能监控、动态 权限控制、代码调试等。
优点
- 织入的代码都是Java代码没有过多的学习难度
缺点
- 无法织入第三方的库
- 由于定义的切点依赖编程语言,该方案无法兼容 Lambda 语法
使用
AOP只是个概念的定义有很多库都可以实现。例如Javapoet/AspectJ。使用的方法都很相似这里只介绍Javapoet。 防不胜防来啦这部分会用InjectExtra为例解释
标记需要操作的位置
通常会使用一个注解去表示 也可以对固定方法进行织入
InjectExtra("data")
String data;
在编译过程中寻找标记
遍历类中所有被注解的元素并生成代码写入
AutoService(Processor.class)//自动生成javax.annotation.processing.IProcessor 文件
@SupportedSourceVersion(SourceVersion.RELEASE_8)//java版本支持
public class AnnotationProcessor extends AbstractProcessor {
...
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
mAnnotatedClassMap.clear();
try {
//遍历元素找到被标记的方法或变量
for (Element element : roundEnv.getElementsAnnotatedWith(InjectExtra.class)) {
ExtraAnnotationProcessor annotatedClass = getAnnotatedClass(element);
BindExtraField field = new BindExtraField(element);
annotatedClass.addField(field);
}
} catch (IllegalArgumentException e) {
// stop process
return true;
}
for (ExtraAnnotationProcessor annotatedClass : mAnnotatedClassMap.values()) {
//将新生成的文件写入
annotatedClass.generateFinder().writeTo(mFiler);
...
}
...
}
写入规则
- $L for Literals
- $S for Strings
- $T for Types
for (BindExtraField field : mFields) {
// find views
if (isSubtypeOfType(typeMirror, "android.app.Activity")) {
injectMethodBuilder.addStatement("Object $N = target.getIntent().getExtras().get($S)", field.getFieldName(), field.getKey());
} else {
injectMethodBuilder.addStatement("Object $N = target.getArguments().get($S)", field.getFieldName(), field.getKey());
}
injectMethodBuilder.addStatement("if($N!=null)\ntarget.$N = ($T)$N", field.getFieldName(), field.getFieldName(), ClassName.get(field.getFieldType()), field.getFieldName());
}
总结
使用AOP方式织入代码可以说是最简单的方式了。没有语言障碍只需把需要的java代码植入就好了。主要缺陷就是必须在原本的代码中显示调用才可以成功使用,无法无痕使用。