什么是注解

引用《Java编程思想》第20章的注解定义:

注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

元注解

Java还另外提供了四种注解,专门负责新注解的创建,这些注解也被称为元注解(meta-annotation)。

注解 含义
@Target 表示该注解可以用于什么地方。可能的 ElementType 包括:CONSTRUCTOR:构造器的声明,FIELD:域声明(包括enum实例),LOCAL_VARIABLE:局部变量声明 ,METHOD:方法声明 ,PACKAGE:包声明 ,PARAMETER:参数声明,TYPE:类、接口(包括注解类型)、或者enum声明
@Retention 表示需要在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:SOURCE:注解将被编译器丢弃,CLASS:注解在class文件中可用,但会被VM丢弃,RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息
@Documented 将此注解包含在Javadoc中。
@Inherited 允许子类继承父类中的注解。

创建注解

1
2
3
@Target(AnnotationTarget.CLASS)  
@Retention(AnnotationRetention.SOURCE)
annotation class Router(val url: String)

@Target(AnnotationTarget.CLASS)表明只能在类上使用Router
@Retention(AnnotationRetention.SOURCE)表明注解的生存期是源代码编译阶段。

什么是注解处理器

注解处理器可以帮助我们事半功倍,也就是说,更少的代码(注解)神奇地变成了更多的功能。以下是注解处理器的介绍:

  1. 注解处理是javac内置的一个工具,用于在编译时扫描和处理注解。
  2. 它可以创建新的源文件;但是,它不能修改现有的。
  3. 它是轮流完成的。当编译到达预编译阶段时,第一轮开始。如果这一轮生成任何新文件,则下一轮以生成的文件作为其输入开始。这种情况一直持续到处理器处理完所有新文件。

    javac 是java语言编程编译器。全称java compiler。javac工具读由java语言编写的类和接口的定义,并将它们编译成字节代码的class文件。

处理流程如图:
Pasted image 20221028004619

编写注解处理器

注解处理器代码

注解处理器需要在Java or Kotlin library才能使用,因此我们需要建立一个Java or Kotlin library模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import com.bravestsnail.router.annotation.Router  
import com.squareup.kotlinpoet.CodeBlock
import java.util.*
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.RoundEnvironment
import javax.annotation.processing.SupportedSourceVersion
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
import javax.lang.model.element.Modifier
import javax.lang.model.element.TypeElement

@SupportedSourceVersion(SourceVersion.RELEASE_8)
class RouterProcessor : AbstractProcessor() {
override fun getSupportedAnnotationTypes() =
mutableSetOf(Router::class.java.canonicalName)

/**
* 处理注解
*
* @param annotations 注解元素
* @param roundEnv 查询包含特定注解的被注解元素
* @return
*/
override fun process(
annotations: MutableSet<out TypeElement>?,
roundEnv: RoundEnvironment
): Boolean {
//TODO
return true
}
  1. @SupportedSourceVersion 指定此处理器支持 Java 8
  2. 所有注解处理器都必须继承 AbstractProcessor 类。
  3. getSupportedAnnotationTypes() 定义了该处理器在运行时查找的一组注解。如果目标模块中的任何元素都没有使用该集合中的注解进行注释,则处理器将不会运行。
  4. process 是在每个注解处理轮次中调用的核心方法。
  5. 如果一切顺利,process 必须返回 true

注册注解处理器

展开 processor ▸ src ▸ main,添加一个名为 resources 的新目录。然后在资源中添加一个子目录并将其命名为 META-INF(必须大写字母)。最后,在META-INF添加一个命名为 services的子目录。在services添加一个空文件并将其命名为 javax.annotation.processing.Processor
Pasted image 20221028005400
文件的内容是注解处理器的全限定名称,如下

1
com.bravestsnail.router.processor.RouterProcessor

除了手动注册的方式外,Google提供了AutoService自动注册工具,通过以下方式依赖:

1
implementation "com.google.auto.service:auto-service:1.2.1"

为注解处理器添加自动注册注解

1
2
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8) class RouterProcessor : AbstractProcessor()

生成代码

通过KotlinPoet库,可以生成Kotlin代码;生成Java代码可以使用JavaPoet

扫描包下的类

[[Android 扫描包下类]]

github代码