APT——Annotation-Processor-Tool)

什么是 APT

APT 中文翻译为“注解处理器”,顾名思义是用来处理注解的。怎么处理呢?Java 在编译期间会扫描代码中的注解,并给开发者提供相应的 API 以便于把扫描到的注解信息提供给开发者使用,从而完成自定义的功能。

APT 的用途

APT 将扫描到注解信息提供给开发者后,开发者就可以利用这些注解信息来生成 Java 文件,在这个 Java 文件中可以编写自己想实现的功能,而生成的这个 Java 文件将和已有的 Java 源代码一起参与编译。最常见的使用场景就是用 APT 来生成一些有规律可循的代码,从而减少重复劳动的成本,提高效率。例如 ButterKnife, Retrofit, GreenDao 已经 Google 推出的 Room 等,都是依赖 APT 来完成。

怎么使用

创建注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS) 
public @interface Environment {
    String url();
    String alias() default "";
    boolean isRelease() default false;
}

创建注解处理类

Java 给我们提供的口子是一个叫 AbstractProcessor 的抽象类,我们要继承这个类。

public class DemoCompilerDebug extends AbstractProcessor {

    /**
     * 它会被注解处理工具调用,以 ProcessingEnvironment 作为参数。
     * ProcessingEnvironment 提供了一些实用的工具类 Elements, Types 和 Filer。
     * 我们在后面将会使用到它们。
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }    

    /**
     * 这类似于每个处理器的 main()方法。你可以在这个方法里面编码实现扫描,
     * 处理注解,生成 java 文件。使用 RoundEnvironment 参数,
     * 你可以查询被特定注解标注的元素。
     */
    @Override
    public boolean process(Set<? extends TypeElement> annoations,
                           RoundEnvironment env) {
        return false;
    }

    /**
     * 在这个方法里面你必须指定哪些注解应该被注解处理器注册。
     * 注意,它的返回值是一个String集合,包含了你的注解
     * 处理器想要处理的注解类型的全称。换句话说,
     * 你在这里定义你的注解处理器要处理哪些注解。
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotataions = new LinkedHashSet<String>();
        annotataions.add(Module.class.getCanonicalName());
        return annotataions;
    }

    /**
     * 用来指定你使用的 java 版本。
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

}

怎么运行起来

我们自己写的代码安装到设备上点击启动就从 main() 方法入口开始运行了,但是我们写的注解处理类是怎么运行起来的呢?它怎么能做到在编译时就生成代码的呢?

javac 启动了一个完整的 java 虚拟机来运行注解处理器。那 javac 怎么知道我们自己写的注解处理类呢?这就需要我们向 javac 进行注册,怎么注册呢?

这就需要我们在 META-INF/services 目录下添加一个特殊文件 javax.annotation.processing.Processor,整个目录结构如下:

-com
    -demo
        -DemoCompilerDebug.class
-META-INF
    -services
        -javax.annotation.processing.Processor

javax.annotation.processing.Processor 文件的内容是一个列表,每一行是一个注解处理器的全称。例如:

com.demo.DemoCompilerDebug

其实有一种更简单的方式就是在我们写的注解处理器类上添加一个注解来自动生成上面的注册文件。

dependencies {
    api 'com.google.auto.service:auto-service-annotations:1.0.1'
    annotationProcessor 'com.google.auto.service:auto-service:1.0.1'
}

修改注解处理类

import com.google.auto.service.AutoService;

@AutoService(Processor.class)
public class DemoCompilerDebug extends AbstractProcessor {
   ...
}

只需要添加上面一个注解就可以自动生成 javax.annotation.processing.Processor 文件,这里也能看出我们其实是在注解处理器上依赖了其他的注解处理器。

发布日期:
分类:开发

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注