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<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false;
    }

    /**
     * 用来表明注释处理器支持支持的注解类型
     *
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> 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机制
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容