前言
近些年,编译期插桩技术在Android圈越来越普遍。无论是可以生成JAVA源码的ButterKnief、Dagger,还是操作字节码的VirtualAPK,甚至是新兴的语言Kotlin都用到了编译期插桩技术。学习这门技术对我们理解这些框架的原理十分有帮助。另外,我们通过这种技术可以抽离出复杂、重复的代码,降低程序耦合性,提高代码的可复用性,提高开发效率。因此,了解编译期插桩技术十分必要。在介绍这项技术之前,我们先来了解一下Android代码的编译过程以及插桩位置。话不多说,直接上图。
APT
APT(Annotation Processing Tool)是一种编译期注解处理器。它通过定义注解和处理器来实现编译期生成代码的功能,并且将生成的代码和源代码一起编译成.class文件。
代表框架:ButterKnife、Dagger、ARouter、EventBus3、DataBinding、AndroidAnnotation等。
在介绍如何应用APT技术之前,我们先来了解一些相关的知识。
一、Element
1.简介
Element
是一种在编译期描述.java文件静态结构的一种类型,它可能表示一个package、一个class、一个method或者一个field。Element
的比较应该使用equals
,因为编译期间同一个Element
可能会用两个对象表示。JDK提供了以下5种Element
。
2.Element的存储结构
编译器采用类似Html的Dom树来存储Element。我们用下面的Test.java
来具体说明。
//PackageElement
package me.zhangkuo.compile;
//TypeElement
public class Test {
//VariableElement
private String name;
//ExecutableElement
private Test(){
}
//ExecutableElement
public void setName(/* TypeParameterElement */ String name) {
this.name = name;
}
}
Test.java
用Element树结构描述如下:
我们可以看到 setName(String name)
的ExecutableElement
中并没有子节点TypeParameterElement
。这是因为TypeParameterElement
没有被纳入到Element
树中。不过我们可以通过ExecutableElement
的getTypeParameters()
方法来获取。
此外,再给大家介绍两个Element中十分有用的方法。
public interface Element extends AnnotatedConstruct {
//获取父Element
Element getEnclosingElement();
//获取子Element的集合
List<? extends Element> getEnclosedElements();
}
二、TypeMirror
Element
有一个asType()
方法用来返回TypeMirror
。TypeMirror
表示 Java 编程语言中的类型。这些类型包括基本类型、声明类型(类和接口类型)、数组类型、类型变量和 null 类型。还可以表示通配符类型参数、executable 的签名和返回类型,以及对应于包和关键字 void
的伪类型。我们一般用TypeMirror进行类型判断。如下段代码,用来比较元素所描述的类型是否是Activity的子类。
/**
* 类型相关工具类
*/
private Types typeUtils;
/**
* 元素相关的工具类
*/
private Elements elementUtils;
private