IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 初探Java 注解处理器 (Annotation Processor) -> 正文阅读

[Java知识库]初探Java 注解处理器 (Annotation Processor)

引言

自从Java 引入了注解(Annotation) 的特性以后,我们获得了由它带来的便利,尤其是在Spring当中得到了大量的应用。大部分情况下使用的注解都是运行时通过反射机制来使用它,今天我们不讨论那些在运行时(Runtime)通过反射机制运行处理的注解,而是讨论在编译时(Compile time)处理的注解。

注解处理器(Annotation Processor)是javac的一个工具,它用来在编译时扫描和处理注解(Annotation)。我们可以自定义注解,并注册相应的注解处理器来完成相应的操作,比如大家非常熟悉的lombok就是采用该机制实现的。

AbstractProcessor

每一个处理器都是继承于AbstractProcessor,如下所示:

public class MyProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment env){ }

    @Override
    public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { }

    @Override
    public Set<String> getSupportedAnnotationTypes() { }

    @Override
    public SourceVersion getSupportedSourceVersion() { }

}
  • init(ProcessingEnvironment env): 每一个注解处理器类都必须有一个空的构造函数。这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供很多有用的工具类Elements, TypesFiler
  • process(Set<? extends TypeElement> annotations, RoundEnvironment env): 这相当于每个处理器的主函数main()。在这里写我们的扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让我们查询出包含特定注解的被注解元素。
  • getSupportedAnnotationTypes(): 这里指定这个注解处理器是处理哪些注解的。注意,它的返回值是一个字符串的集合。
  • getSupportedSourceVersion(): 用来指定我们使用的Java版本。通常这里返回SourceVersion.latestSupported()

在Java 7以后,我们也可以使用注解来代替getSupportedAnnotationTypes()getSupportedSourceVersion(),像这样:

@SupportedSourceVersion(SourceVersion.latestSupported())
@SupportedAnnotationTypes({
   // 合法注解全名的集合
 })
public class MyProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment env){ }

    @Override
    public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { }
}

注册处理器

我们可能会问如何让处理器MyProcessor注册到javac中。首先我们必须提供一个.jar文件。就像其他.jar文件一样,打包我们的注解处理器到此文件中。并且,在我们的jar中需要打包一个特定的文件javax.annotation.processing.ProcessorMETA-INF/services路径下。所以,我们的.jar文件看起来就像下面这样:
MyProcessor.jar
----com
--------example
------------MyProcessor.class
----META-INF
--------services
------------javax.annotation.processing.Processor

com.example.MyProcessor  

MyProcessor.jar放到我们的buildpath中,javac会自动检查和读取javax.annotation.processing.Processor中的内容,并且注册MyProcessor作为注解处理器。

上面注册处理器是不是特别的麻烦呢?有没有简单的方式,比如利用一个annotation来搞定?Google就为我们提供了一个这样的annotation:@AutoService(Processor.class)

@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
}
        <dependency>
            <groupId>com.google.auto.service</groupId>
            <artifactId>auto-service</artifactId>
            <version>1.0.1</version>
        </dependency>

在代码的第一行加上@AutoService(Processor.class),它就能自动帮我们生成META-INF/services/javax.annotation.processing.Processor文件

举个栗子:

一、定义一个annotation:

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE, ElementType.FIELD})
public @interface FieldConstant {
}

二、定义一个annotation处理器:

@AutoService(Processor.class)
public class FieldConstantProcessor extends AbstractProcessor {

    // 主要是输出信息
    private Messager messager;

    private JavacTrees javacTrees;

    private TreeMaker treeMaker;
    private Names names;
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        System.out.println("process");
        this.messager = processingEnv.getMessager();
        this.javacTrees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment)processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        System.out.println("process");
        // 拿到被注解标注的所有的类
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(FieldConstant.class);
        //如果是类,则对所有的属性进行修改
        for (Element element : elements) {
            System.out.println("element is " + element.getSimpleName().toString());
        }
        return false;
    }

    /**
     * 本处理器想要处理的注解类型的合法全称
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return new HashSet<String>(Arrays.asList(FieldConstant.class.getCanonicalName()));
    }

    /**
     * 用来指定使用的Java版本
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

}

三、定义一个测试类:

@FieldConstant
public class Test {
    /**
     * 创建时间
     */
    private Date createTime;
    

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}
public class Main {
    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test);
    }
}

通过maven编译Main类,看一下编译的输出:

[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sample ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to D:\code\sample\target\classes
init
process
element is Test
process
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------


四、问题:

为什么process会打印了两次呢?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:12:55  更:2022-09-21 00:18:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:21:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码