APT 介绍
什么是 APT ?
APT 全称 Annotation Processing Tool,翻译过来即注解处理器。引用官方一段对 APT 的介绍:APT 是一种处理注释的工具, 它对源代码文件进行检测找出其中的注解,并使用注解进行额外的处理。
APT 有什么用?
APT 能在编译期根据编译阶段注解,给我们自动生成代码,简化使用。很多流行框架都使用到了APT技术,如 ButterKnife,Retrofit,Arouter,EventBus 等等
APT 工程
1)、APT 工程创建
一般情况下,APT 大致的的一个实现过程:
1、创建一个Java Module ,用来编写注解
2、创建一个Java Module,用来读取注解信息,并根据指定规则,生成相应的类文件
3、创建一个Android Module ,通过反射获取生成的类,进行合理的封装,提供给上层调用
如下图:
这是我的 APT工程,关于 Module名称可以任意取,按照我上面说的规则去进行就好了
2)、Module 依赖
工程创建好后,我们就需要理清楚各个 Module 之间的一个依赖关系:
1、因为 apt-processor 要读取apt-annotation的注解,所以apt-processor需要依赖apt-annotation
//apt-processor 的 build.gradle 文件
dependencies {
implementation project(path: ':apt-annotation')
}
2、app 作为调用层,以上 3 个 Module都需要进行依赖
//app 的 build.gradle 文件
dependencies {
//...
implementation project(path: ':apt-api')
implementation project(path: ':apt-annotation')
annotationProcessor project(path: ':apt-processor')
}
APT工程配置好之后,我们就可以对各个 Module 进行一个具体代码的编写了
apt-annotation 注解编写
这个 Module的处理相对来说很简单,就是编写相应的自定义注解就好了,我编写的如下:
@Inherited
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({
ElementType.TYPE,ElementType.METHOD})
public @interface AptAnnotation {
String desc() default "";
}
apt-processor 自动生成代码
这个 Module 相对来说比较复杂,我们把它分为以下 3 个步骤:
1、注解处理器声明
2、注解处理器注册
3、注解处理器生成类文件
1)、注解处理器声明
1、新建一个类,类名按照自己的喜好取,继承javax.annotation.processing这个包下的 AbstractProcessor类并实现其抽象方法
public class AptAnnotationProcessor extends AbstractProcessor {
/**
* 编写生成 Java 类的相关逻辑
*
* @param set 支持处理的注解集合
* @param roundEnvironment 通过该对象查找指定注解下的节点信息
* @return true: 表示注解已处理,后续注解处理器无需再处理它们;false: 表示注解未处理,可能要求后续注解处理器处理
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
return false;
}
}
重点看下第一个参数中的 TypeElement ,这个就涉及到Element 的知识,我们简单的介绍一下:
Element 介绍
实际上,Java 源文件是一种结构体语言,源代码的每一个部分都对应了一个特定类型的 Element,例如包,类,字段,方法等等:
package com.dream; // PackageElement:包元素
public class Main<T> {
// TypeElement:类元素; 其中 <T> 属于 TypeParameterElement 泛型元素
private int x; // VariableElement:变量、枚举、方法参数元素
public Main() {
// ExecuteableElement:构造函数、方法元素
}
}
Java 的 Element是一个接口,源码如下:
public interface Element extends javax.lang.model.AnnotatedConstruct {
// 获取元素的类型,实际的对象类型
TypeMirror asType();
// 获取Element的类型,判断是哪种Element
ElementKind getKind();
// 获取修饰符,如public static final等关键字
Set<Modifier> getModifiers();
// 获取类名
Name getSimpleName();
// 返回包含该节点的父节点,与getEnclosedElements()方法相反
Element getEnclosingElement();
// 返回该节点下直接包含的子节点,例如包节点下包含的类节点
List<? extends Element> getEnclosedElements();
@Override
boolean equals(Object obj);
@Override
int hashCode();