APT

  • 什么是APT
    APT即为Annotation Processing Tool,它是javac的一个工具,中文意思为编译时注解处理器。

  • 能做什么
    APT可以用来在编译时扫描和处理注解。通过APT可以获取到注解和被注解对象的相关信息,在拿
    到这些信息后我们可以根据需求来自动的生成一些代码,省去了手动编写。


    image.png
  • 解决什么问题
    APT获取注解及生成代码都是在代码编译时候完成的,相比反射在运行时处理注解大大提高了程序性能。

  • 使用场景
    解决一些固定规则生成代码、文件场景

  • 使用该技术第三方框架
    APT技术被广泛的运用在Java框架中,包括 ButterKnife、EventBus 、Dagger2、ARouter路由框架等都运用到APT技术

  • 优缺点

优点(结合javapoet)
对代码进行标记、在编译时收集信息并做处理
生成一套独立代码,辅助代码运行

缺点
可以自动生成代码,但在运行时需要主动调用
如果要生成代码需要编写模板函数

通过以上了解APT了解,探索APT如何使用和实现原理还是相对必要。

APT使用

APT项目需要由至少两个Java Library模块组成,首先,新建一个Android项目,然后File–>New–>New Module,打开如上图所示的面板,选择Java
Library即可。刚才说到一个APT项目至少应该由两个Java Library模块。那么这两个模块分别是什么作用
呢?

  1. 先需要一个Annotation模块,这个用来存放自定义的注解。
  2. 另外需要一个Compiler模块,这个模块依赖Annotation模块。
  3. 项目的App模块和其它的业务模块都需要依赖Annotation模块,同时需要通过
    annotationProcessor依赖Compiler模块。


    image.png

app模块的gradle中依赖关系如下:

implementation project(path: ':annotations')
annotationProcessor project(path: ':annotation_compiler')
未命名文件.png

为什么要强调上述两个模块一定要是Java Library?如果创建Android Library模块你会发现
不能找到AbstractProcessor这个类,这是因为Android平台是基于OpenJDK的,而OpenJDK中
不包含APT的相关代码。因此,在使用APT时,必须在Java Library中进行。

APT的核心是AbstractProcessor类,继承AbstractProcessor,实现默认的方法

/**
 * 自定义注解处理器。因为Android平台可能会有兼容问题,建议使用重写getSupportedAnnotationTypes方法指定支持的注解类型
 */
public class CustomProcessor extends AbstractProcessor {
    private Types typeUtils;
    /**
     * 代表程序的元素,例如包、类或者方法。每个Element代表一个静态的、语言级别的构件。它只是结构化的文本,他不是可运行的.可以理解为一个签名
     */
    private Elements elementUtils;
    private Filer filer;
    /**
     * 输出错误信息,不可以抛出Exception
     */
    private Messager messager;

    /**
     * 初始化相关工具
     *
     * @param env
     */
    @Override
    public synchronized void init(ProcessingEnvironment env) {
        super.init(processingEnv);
        elementUtils = env.getElementUtils();
        filer = env.getFiler();
        typeUtils = env.getTypeUtils();
        messager = env.getMessager();
    }

    /**
     * 生成java代码,
     *
     * @param annotations 指定getSupportedAnnotationTypes()
     * @param roundEnv
     * @return
     */
    @Override
    public boolean process(Set annotations, RoundEnvironment roundEnv) {
        return false;
    }

    /**
     * 用来表明注释处理器支持支持的注解类型
     *
     * @return
     */
    @Override
    public Set getSupportedAnnotationTypes() {
        Set annotataions = new HashSet<>();
        //这里支持测试使用注解
        annotataions.add(CustomAn.class.getCanonicalName());
        return annotataions;
    }

    /**
     * 用来表明注释处理器支持到的JAVA版本
     *
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        //最新Java版本
        return SourceVersion.latestSupported();
    }
}

继承了AbstractProcessor类完成,因为注解处理器,是java编译器(简称javac)启动一个完整Java虚拟机来运行注解处理器,那我们就需要把处理器注册到javac

  • 注册注解处理器
    将处理器CustomProcessor注册到javac中。
    原始方法:
    你必须提供一个.jar文件。就像其他.jar文件一样,你打包你的注解处理器到此文件中。并且,在你的jar中,你需要打包一个特定的文件javax.annotation.processing.Processor到META-INF/services路径下。过程比较复杂具体看,
    自动注册方法:
    好在google帮我们开发好了自动注册处理的脚步。我们需要在Android项目中引入
dependencies {
    implementation 'com.google.auto.service:auto-service:1.0.1'
    annotationProcessor 'com.google.auto.service:auto-service:1.0.1'
}

在注解处理器中加上“@AutoService(Processor.class)” 注解就好了:

@AutoService(Processor.class)
public class CustomProcessor extends AbstractProcessor {
....//省略代码
}

现在在来看最重要的AbstractProcessor#process()方法实现,如何自定义注解处理了。大概步骤为:

  1. 存储使用注解类和使用地方
  2. 生成java文件代码
  • 解析注解生产相关代码
    process()主要是用来获取注解信息的方法,通过参数RoundEnvironment获取所有的自定义注解的信息,然后通过注解信息做我们想做的事情。可参考ButterKnife源码做相关处理

扩展

APT、android-apt 和 annotationProcessor 的区别

  • APT是什么?
    apt是 Annotation Processing Tool 的缩写,编译时注解处理器,用于编译时对注解进行解析,自动生成代码,并编译代码生成class文件,大体就是这个过程。
  • android-apt是什么?
    android-apt是第三方开源的注解处理框架,因为一开始Android没有默认的支持注解。dagger、ButterKnife等流行的注解框架,都是用的android-apt进行的注解处理。
  • annotationProcessor是什么?
    在Android studio Gradle插件2.2版本发布后,Google开始支持注解处理,而android-apt作者宣布不再维护更新,建议使用官方提供的annotationProcessor。
Andoroid如需添加使用了注解处理器的库的依赖,您必须使用 `annotationProcessor` 配置将其添加到注解处理器的类路径。
这是因为,使用此配置可以将编译类路径与注解处理器类路径分开,从而提高构建性能。
如果 Gradle 在编译类路径上找到注解处理器,
则会禁用避免编译功能,这样会对构建时间产生负面影响(Gradle 5.0 及更高版本会忽略在编译类路径上找到的注释处理器)。
如果 JAR 文件包含以下文件,则 Android Gradle 插件会假定依赖项是注释处理器:
`META-INF/services/javax.annotation.processing.Processor`。 
如果插件检测到编译类路径上包含注解处理器,则会产生构建错误。
  • android-apt 和 annotationProcessor异同
    相同:两者都是apt 工具,只在编译的时候执行依赖的库,但是库最终不打包到apk中。
    不同:
    1)前者只支持 javac 的编译方式,而后者支持 javac 和 jack 两种。
    2)Android Gradle 插件2.2版本后已经内置annotationProcessor,不需要引入,直接在build.gradle文件配置使用。
  • kapt(Kotlin 注解处理)
  • 自定义Java注解处理器
  • 编译时注解处理器APT详解
  • apt使用策略模式思想,spi机制

你可能感兴趣的:(APT)