Android APT工作原理(annotationProces
前言
在之前的文章Android编译时注解--入门篇(AbstractProcessor、APT)中介绍了通过APT技术实现仿ButterKnife编译时注解的功能。虽然尽可能做到了很详细的介绍(那篇文章长达2500+字),但是仍然留下了一些疑问,本文就是专门来解释这些问题的。
目前市面上大多数讲apt的文章,大多数是讲一个编译时注解的demo,但是很少人把apt工作原理说清楚,对于下面这几个问题更是几乎没人解释过原因。如果你不想只学一点用法,不想面试被卡住,想让自己变的更强,你应该把apt的工作原理搞清楚,本文值得你阅读
一些疑问
- 注解处理器processor为什么要在META-INF注册?
- 注解处理器processor是如何被系统调用的?
- 注解申明和注解处理器为什么要分Module处理?
- apt项目不会增加apk体积?
先来回顾一下之前项目的部分目录结构
image.png先明确一些概念:
AbstractProcessor
是抽象处理器,开发apt时都必须继承这个类来生成.java
文件,实现的这个类后叫做注解处理器,也就是这里的ButterKnifeProcessor
。
Q1:注解处理器processor为什么要在META-INF注册?
META-INF
的作用
META-INF, 相当于一个信息包,用于存放一些meta information相关的文件。用来配置应用程序、扩展程序、类加载器和服务manifest.mf文件,在用jar打包时自动生成。
在之前的文章中说过,通过@AutoService(Processor.class)
注解把注解处理器ButterKnifeProcessor
注册到META-INF/services中,这里的包名是META-INF/services/javax.annotation.processing.Processor
,
这个文件的内容是
com.zx.processor.ButterKnifeProcessor
这个包名其实就是@AutoService(Processor.class)
里面的Processor
类;而文件内容就是注解处理器。
在编译时,java编译器(javac)会去META-INF中查找实现了的AbstractProcessor的子类,并且调用该类的process函数,最终生成.java
文件。其实就像activity需要注册一样,就是要到META-INF注册 ,javac才知道要给你调用哪个类来处理注解。
Q2:注解处理器processor是如何被系统调用的?
一些细心的同学应该发现了这个问题,我们并没有手动调用AbstractProcessor
这个注解处理器类,那系统是什么时间调用的?又是如何调用的?这其实就牵扯到apt工作机制。
在上一问中,我们已经了解到,在编译时javac会查找所有的 在META_INF 中注册的注解处理器来处理注解。
到这里,好像有点清楚了,大概知道javac会去找到Processor并调用。但是呢还是没找到直接源头,因为它不像我们面向对象编程中可以准确追踪到是哪个对象调用的。
别着急,先来看这么个东西.
是我项目中使用到注解的app.Gradle
dependencies {
implementation project(':annotation')
implementation project(':inject_api')
//gradle3.0以上apt的实现方式
annotationProcessor project(':processor')
}
这里的annotationProcessor
有点特别,没错,它是APT实现方案的一种。这里简单介绍一下:
APT实现方案
android-apt
和annotationProcessor
功能是一样的,都是apt的实现方案,前者是个人开发者提供,比较早(现在不再维护了),后者是google官方开发的内置在gradle
里的apt。
annotationProcessor是APT工具中的一种,是google开发的内置框架,不需要引入,可以直接在build.gradle
文件中使用。
只有在你使用注解的地方引入了annotationProcessor
,系统才会主动调用注解处理类Processor
,才会最终生成如下的.java
文件
这里先简单总结一下:
2.1、在完成注解处理类Processor
之后,需要做2件事情:
- 1、在META-INF目录下注册
Processor
; - 2、在项目中使用注解的地方添加apt工具
annotationProcessor
2.2、APT 4要素
注解处理器(AbstractProcess)+ 代码处理(javaPoet)+ 处理器注册(AutoService)+ apt(annotationProcessor)
APT(Annotation Processing Tool)总结
首先,APT是javac提供的一种工具,它在编译时扫描、解析、处理注解。它会对源代码文件进行检测,找出用户自定义的注解,根据注解、注解处理器和相应的apt工具自动生成代码。这段代码是根据用户编写的注解处理逻辑去生成的。最终将生成的新的源文件与原来的源文件共同编译(注意:APT并不能对源文件进行修改操作,只能生成新的文件,例如往原来的类中添加方法)。具体流程图如下图所示:
APT技术的使用,需要我们遵守一定的规则。大家先看一下整个APT项目项目构建的一个规则图,具体如下所示:
Q3:注解申明和注解处理器为什么要分Module处理?
先来回顾一下之前的项目结构:
-
annotation
:申明注解 (java lib) -
processor
:注解处理器(java lib) -
inject_api
:调用处理器中生成的类 (android lib) -
app
:项目使用 (android lib)
我们都知道注解处理器都需要继承AbstractProcessor
类,但是AbstractProcessor
是JDK中的类,不在android sdk中,所以需要放在单独的java lib中;而processor
中需要依赖自定义注解,把annotation
抽成一个独立的lib,便于维护。
那注解声明和注解处理为什么要分开呢?可不可以放在一起?
先说结论:可以放在一起,放在一起对功能上没有什么影响;但是一般不放在一起,原因如下:
我们都知道
processor
的作用是:在编译器解析注解、生成新的.java
文件。这个lib只在编译器用到,是不会被打包进apk的。对于调用者来说,你只是想使用这个注解,而不希望你已经编译好的项目中引进注解处理器相关的内容,所以为了不引入没必要的文件,我们一般选择将注解声明和注解处理分开处理。
到这里apt相关知识就说完了,我们也可以理解为什么ButterKnife
这种注解库不会增加项目体积了。
想了解更多apt知识,可以参考:
https://www.jianshu.com/p/b6b3283968e0
感谢
你必须知道的APT、annotationProcessor、android-apt、Provided、自定义注解
呕心沥血之作,喜欢的朋友点个赞,刷个666,就是对我的最大支持!