APT-编译期解析注解

简介

APT即Annotation Processing Tool,它的做用是在项目编译期间解析代码中的注解,经过获取注解的信息,配合代码生成工具生成java文件。当项目中有书写大量相同功能重复代码的需求时,能够经过APT进行AOP编程。如ButterKnife EventBus3都是经过APT技术实现的java

自定义注解处理器

新建module,类型选择java-lib,建立Java类并继承AbstractProcessor. 这里有几个重要的方法须要重写编程

  1. SourceVersion getSupportedSourceVersion() 用来指定你使用的Java版本。一般这里返回SourceVersion.latestSupported()
@Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
复制代码
  1. Set getSupportedAnnotationTypes() 返回类的全路径集合,表示处理器须要处理的注解集合
@Override
    public Set<String> getSupportedAnnotationTypes() {
        HashSet<String> supportTypes = new HashSet<>();
        supportTypes.add(AnnotationA.class.getCanonicalName());
        supportTypes.add(AnnotationB.class.getCanonicalName());
        return supportTypes;
    }
复制代码
  1. void init(ProcessingEnvironment processingEnvironment) 注解处理器的初始化阶段,能够经过该方法获取处理注解和生成Java文件的工具类
private Filer mFilerUtils;       // 文件管理工具类,能够用于生成java源文件
    private Types mTypesUtils;    // 类型处理工具类,
    private Elements mElementsUtils;  // Element处理工具类,获取Element的信息
    private Messager mMessager;  //用于打印信息

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mFilerUtils = processingEnvironment.getFiler();
        mTypesUtils = processingEnvironment.getTypeUtils();
        mElementsUtils = processingEnvironment.getElementUtils();
        mMessager = processingEnvironment.getMessager();
    }
复制代码
  1. boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)是注解处理器必须实现的方法,全部获取注解信息和生成Java文件的逻辑都在这里实现,方法会两个参数set和roundEnvironment,咱们能够经过这两个参数的api获取注解类的信息
@Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        //遍历项目工程,找出全部注解AnnotationA的元素
        Set<? extends Element> annotationA =  roundEnvironment.getElementsAnnotatedWith(AnnotationA.class);
        return false;
    }
复制代码

注解解析时经常使用接口

  • Element

element是表明程序的一个元素,这个元素能够是:包、类/接口、属性变量、方法/方法形参、泛型参数。element是java-apt(编译时注解处理器)技术的基础,所以若是要编写此类框架,熟悉element是必须的。api

查看接口源码框架

public interface Element extends AnnotatedConstruct {
    //返回一个TypeMirror是元素的类型信息,包括包名,类(或方法,或参数)名/类型
    //在生成动态代码的时候,咱们每每须要知道变量/方法参数的类型,以便写入
    //正确的类型声明
    TypeMirror asType();
    //返回注解应用到元素的种类,包括包,类,方法,参数,变量等
    ElementKind getKind();
    //获取修饰符 public static final等关键字
    Set<Modifier> getModifiers();
    //获取名字,不带报名
    Name getSimpleName();
    //返回外层的元素
    Element getEnclosingElement();
    //返回该元素直接包含的子元素,一般对一个PackageElement而言,它能够包含Type
    //Element;对于一个TypeElement而言,它可能包含属性VariableElement
    //方法ExecutableEleme
    List<? extends Element> getEnclosedElements();

    boolean equals(Object var1);

    int hashCode();
    //获取该元素上的注解的类型信息,AnnotationMirror相似于TypeMirror
    List<? extends AnnotationMirror> getAnnotationMirrors();
    //根据传入的注解类型获取该元素上的注解
    <A extends Annotation> A getAnnotation(Class<A> var1);

    <R, P> R accept(ElementVisitor<R, P> var1, P var2);
}
复制代码

element的子接口有,也是就是源码中getKind()能够获取的类型ide

  1. packageElement 表示包
  2. TypeElement 表示类,接口,注解
  3. VariableElement 表示变量,参数
  4. TypeParameterElement 表示泛型
  5. ExecutableElement 表示方法体

element所表明的元素只在编译期可见,用于保存元素在编译期的各类状态。工具

  • TypeMirror typeMirror表示的是java层面的类型
@AnnotaionA
int A = 0;
复制代码

此时VariableElement A元素能够经过asType,返回对应的java层面int相关的类型信息ui

注册processor

自定义的Processor须要将它注册给java编译器,编译期在编译时才能识别。 在src/main目录下建立resources/META-INF/services/javax.annotation.processing.Processor文件 在javax.annotation.processing.Processor中写入自定义的Processor的全名(com.xxx.xxx.processor),若是有多个Processor的话,每一行写一个。spa

配置完成后rebuild项目,就能够经过process解析注解和生成java文件了code

相关文章
相关标签/搜索