注解处理器(Annoation Processor)

前言

Java中的注解(Annotation)如果要被识别,离不开注解处理器。所以有必要来了解一下。

注解处理器

注解处理器(Annotation Processor)是javac的一个工具,不管是运行时注解还是编译时注解,都会通过处理器在编译时进行扫描和处理注解。
Java中有默认的注解处理器,使用者也可以自定义注解处理器,注册后使用注解处理器处理注解,最终达到注解本身起到的效果。

注解处理器将标记了注解的类,变量等作为输入内容,经过注解处理器处理,生成想要生成的java代码。所以处理器可以理解为就是一个生成代码的工具,只是是通过注解的规则生成。生成后的代码,可以看作是同一般代码,最终被编译。

自定义处理器

如果java提供的注解处理器不能满足需求,那就可以自定义。自定义的注解处理器要遵循java中标准处理器的接口。

1.创建工程
首先注解处理器需要javax包的支持,Android环境下是访问不到javax包的。
需要创建Java Library包来提供javax环境,另外注解处理器要被打包进jar包里面才能被系统识别,这就是选用ava Library的原因,目前注解注解框架均是如此。
Android studio中,选择创建新的module,选择Java Library**(该lib是注解处理器的lib、另外注解本身的lib也需要单独创建一个annotation的lib,此处就不讲了。)**
在这里插入图片描述

2. 继承虚处理器AbstractProcessor
AbstractProcessor在JDk的rt,jar中:
在这里插入图片描述
每个处理器都要继承该类,如:

package com.starcor.processor.router;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;

public class RouterProcessor  extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        return false;
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }
}

  • init(ProcessingEnvironment processingEnvironment):
    每一个注解处理器类都必须有一个空的构造函数。然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供很多有用的工具类Elements, Types和Filer。后面我们将看到详细的内容。
  • process(Set<? extends TypeElement> annotations, RoundEnvironment env):
    这相当于每个处理器的主函数main()。扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素。后面我们将看到详细的内容。
  • getSupportedAnnotationTypes():
  • 这里你必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。换句话说,你在这里定义你的注解处理器注册到哪些注解上。
  • getSupportedSourceVersion():
  • 用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。然而,如果你有足够的理由只支持Java 6的话,你也可以返回SourceVersion.RELEASE_6。我推荐你使用前者。
    在Java 7中,你也可以使用注解来代替getSupportedAnnotationTypes()和getSupportedSourceVersion(),像这样:
    @SupportedAnnotationTypes(“com.starcor.annotation.RouterAnnotation”),其中括号内内容表示要处理的注解名称,要写全名。
package com.starcor.processor.router;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;

@SupportedAnnotationTypes("com.starcor.annotation.RouterAnnotation")
public class RouterProcessor  extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        return false;
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }
}

3. 注册处理器
以上已经把完成了处理器的工作,但是处理器要被识别 ,还需要被注册。
注册方式一:手动注册
在使用注解处理器需要先声明,步骤:
1、需要在 processors 库的 main 目录下新建 resources 资源文件夹;
2、在 resources文件夹下建立 META-INF/services 目录文件夹
在这里插入图片描述

在文件java.lang.Process中增加注册器路径名:
com.starcor.processor.router.RouterProcessor

方式二:自动注册
google提供了一个注册处理器的库AutoService。帮助将要编译的处理器进行编译。
compile ‘com.google.auto.service:auto-service:1.0-rc2’

apply plugin: 'java-library'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"

dependencies {
    compile 'com.google.auto.service:auto-service:1.0-rc2'
}

然后再processor中使用注解:
@AutoService(Processor.class)
public class RouterProcessor extends AbstractProcessor {

}

此时编译时候就会生成文件目录如下:***(但是我这边验证使用AutoService自动注册存在问题,生成的文件为java.lang.Process,暂不明白什么原因,所以使用的手动注册方式)***
在这里插入图片描述
处理器对全局代码的扫描处理流程
注解处理器对工程代码的扫描是多次的,可以注意到AbstractProcessor的process()方法的输入参数有一个是RoundEnvironment,这个代表一次扫描的结果。
4. 使用处理器
再应用工程中,测试注解处理器。
在工程的build.gradle中增加使用的处理器:
implementation project(’:annotation’)
annotationProcessor project(’:Processor’)

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:26.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    annotationProcessor project(':Processor')
    implementation project(':annotation')
}

验证是否执行了注解处理器,可以init中增加打印,在gradle console中可以查看到:

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        messager = processingEnvironment.getMessager();//获取信息打印工具
        messager.printMessage(Diagnostic.Kind.NOTE, "TestProcessor=============init");//打印信息,在Gradle Console可以看到打印信息,如果第一个参数写成Kind.ERROR将会信息中断
    }

打印如下:
在这里插入图片描述整个工程目录如下:
在这里插入图片描述
app是使用注解的app模块; Processor是处理注解生成动态代码的模块;annotation是注解定义模块;
生成的文件目录一般为:
在这里插入图片描述

总结

以上说明了怎么实现一个自定义的注解处理器,但是注解处理器根本没有做什么事情。编译时注解一般是要生成java的class文件,那么怎么生成呢?我们可以借助javapoet来实现。javapoet是一个生成java源文件的框架。后面来讲一下生成规则。
所以,一般情形,增加一个自定义注解处理器,离不开3个概念:

procesor:注解处理类,另外AutoService和javapoet来完成源代码的生成
AutoService :作用是注解 processor 类,并对其生成 META-INF 的配置信息.
javapoet:用于生成java.class文件

在这里插入图片描述

强烈推荐:
https://www.jianshu.com/p/7af58e8e3e18
https://blog.csdn.net/hj7jay/article/details/52180023
https://www.jianshu.com/p/2d6fdbb6ead2
https://blog.csdn.net/qq_27070117/article/details/82873351
https://blog.csdn.net/ai_te_xiao/article/details/79374546
https://blog.csdn.net/ddxxii/article/details/85143830

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java注解处理器(Annotation Processor)是Java语言提供的一种机制,用于在编译时扫描和处理注解信息。它可以自动扫描Java源代码中的注解,生成新的Java代码、XML文件或者其他类型的文件。 Java注解处理器可以用于很多方面,比如生成代码、检查代码、生成文档等等。下面我们来详细介绍一下Java注解处理器的使用。 1. 创建注解 首先,我们需要定义一个注解注解通常用来标记Java源代码中的某个元素,比如类、方法、变量等。注解的定义方式如下: ```java @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface MyAnnotation { String value(); } ``` 上面的代码定义了一个注解`MyAnnotation`,它有一个属性`value`。这个注解只能用于类上,它的生命周期为源代码级别。 2. 编写注解处理器 接下来,我们需要创建一个注解处理器,用来扫描和处理Java源代码中的注解信息。注解处理器必须实现`javax.annotation.processing.Processor`接口,同时还需要用`@SupportedAnnotationTypes`注解指定要处理的注解类型,用`@SupportedSourceVersion`注解指定支持的Java版本。 ```java @SupportedAnnotationTypes("MyAnnotation") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (TypeElement annotation : annotations) { Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(annotation); for (Element element : elements) { if (element.getKind() == ElementKind.CLASS) { String className = element.getSimpleName().toString(); String packageName = processingEnv.getElementUtils().getPackageOf(element).toString(); String value = element.getAnnotation(MyAnnotation.class).value(); System.out.println("Found class " + packageName + "." + className + ", value = " + value); } } } return true; } } ``` 上面的代码是一个简单的注解处理器,它可以处理`MyAnnotation`注解,输出被注解的类的信息,包括类名、包名和注解的属性值。 3. 注册注解处理器 最后,我们需要在`META-INF/services/javax.annotation.processing.Processor`文件中注册注解处理器,这样编译器才能够找到它并使用它。这个文件的内容就是注解处理器的全限定类名,比如: ``` com.example.MyAnnotationProcessor ``` 4. 编译Java源代码 现在我们就可以使用注解处理器了。对于一个Java项目,我们需要将注解处理器打包成一个Jar文件,并将它添加到项目的classpath中。然后,在编译Java源代码时,我们需要指定`-processor`选项来告诉编译器要使用哪个注解处理器,比如: ``` javac -cp my-processor.jar -processor com.example.MyAnnotationProcessor MyAnnotatedClass.java ``` 上面的命令将会编译`MyAnnotatedClass.java`文件,并使用`com.example.MyAnnotationProcessor`注解处理器来处理其中的注解信息。 总结 Java注解处理器是一个非常强大的工具,它可以帮助我们自动化生成代码、检查代码、生成文档等等。使用注解处理器可以减少手写重复代码的工作量,提高代码的可维护性和可读性。需要注意的是,注解处理器只能用于编译时,不能用于运行时。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值