注解的处理除了可以在运行时通过反射机制处理外,还可以在编译期进行处理。在编译期处理注解时,会处理到不再产生新的源文件为止,之后再对所有源文件进行编译。

Java5中提供了apt工具来进行编译期的注解处理。apt是命令行工具,与之配套的是一套描述“程序在编译时刻的静态结构”的API:Mirror API(com.sun.mirror.*)。通过Mirror API可以获取到被注解的Java类型元素的信息,从而提供自定义的处理逻辑。具体的处理工具交给apt来处理。编写注解处理器的核心是两个类:注解处理器(com.sun.mirror.apt.AnnotationProcessor)、注解处理器工厂(com.sun.mirror.apt.AnnotationProcessorFactory)。apt工具在完成注解处理后,会自动调用javac来编译处理完成后的源代码。然而,apt工具是oracle提供的私有实现(在JDK开发包的类库中是不存在的)。在 Java8中,已经移除了 APT 工具;在JDK6中,将注解处理器这一功能进行了规范化,形成了java.annotation.processing的API包,Mirror API则进行封装,形成javax.lang.model包。注解处理器的开发进行了简化,不再单独使用apt工具,而将此功能集成到了javac命令中。(当前开发使用的JDK版本一般都在6以上,故对apt工具不做研究)。

编译期注解处理器

通过一个示例程序来解释编译期注解处理器的使用(javac工具来处理)。

使用注解处理器将给定的java源文件生成对应的接口文件,仅对类中的公共方法抽象成接口中的方法。

2.1、定义注解@GenerateInterface

定义注解的保留范围为源代码级别,仅包含一个注解元素suffix(),表名生成接口的后缀名。

2.2、编写测试Java类

2.2.1、编写测试类Teacher:

类Teacher标注上了注解@GenerateInterface,指定生成接口的后缀名为”IntSuffix”。按照预期,生成的接口的名称应为TeacherIntSuffix。

2.2.2、编写测试类Doctor

类Doctor未使用注解,注解处理器将不会为该类生成对应的接口文件。

2.3、编写注解处理器

JDK6中提供的注解处理工具框架的主要类包为javax.annotation.processing。处理器的核心接口为:javax.annotation.processing.Processor,还提供了一个此接口的实现类:javax.annotation.processing.AbstractProcessor。处理接口提供了一个核心处理方法process(),用于开发者实现自己的处理逻辑(用于处理先前round中产生的注解)。

process()方法有一个boolean类型的返回值,若返回false,表示本轮注解未声明并且可能要求后续其它的Processor处理它们;若返回true,则代表这些注解已经声明并且不要求后续Processor来处理它们。

2.3.1、AbstractProcessor虚拟类

AbstractProcessor主要实现了Processor接口的主要方法:

init(ProcessingEnvironment processingEnv)方法:使用处理环境类初始化Processor类,将ProcessingEnvironment环境存入成员变量processingEnv中,可供子类使用。实现如下:

getSupportedOptions()方法:获取通过注解@SupportedOptions设置的可支持的输入选项值(-A参数),具体实现如下:

getSupportedAnnotationTypes()方法:指定注解处理器可解析的注解类型,结果元素可能是某一受支持注释类型的规范(完全限定)名称。它也可能是 “name.*” 形式的名称,表示所有以 “name.” 开头的规范名称的注释类型集合。最后,”*” 自身表示所有注释类型的集合,包括空集。注意,Processor 不应声明 “*”,除非它实际处理了所有文件;声明不必要的注释可能导致在某些环境中的性能下降。具体实现如下:

getSupportedSourceVersion()方法:指定该注解处理器支持的最新的源版本,默认为版本6。具体实现如下:

2.3.2、Filer接口

完全类名:javax.annotation.processing.Filer,注解处理器可用此创建新文件(源文件、类文件、辅助资源文件)。由此方法创建的源文件和类文件将由管理它们的工具(javac)处理。

2.3.3、Messager接口

完全类名:javax.annotation.processing.Messager,注解处理器用此来报告错误消息、警告和其他通知的方式。可以为它的方法传递元素、注解、注解值,以提供消息的位置提示,不过,这类位置提示可能是不可用的,或者只是一个大概的提示。打印错误种类的日志将会产生一个错误。

注意:打印消息可能会出现在System.out、System.out中,也可能不是。也可以选择在窗口中显示消息。

2.3.4、自定义注解处理类CreateInterfaceProcessor

编写真正的注解处理程序CreateInterfaceProcessor,为了演示用,尽量保持处理逻辑的简单性,在此处忽略方法的返回类型和参数的判断,以下具体逻辑:

循环每一个需要编译处理的类(即Teacher、Doctor),找出有注解@GenerateInterface标识的类(即Teacher)。

找到Teacher类中所有的public方法。

根据类名和方法名,使用Filer对象生成源码类。

具体代码实现如下:

2.4、执行注解处理器

注解处理器编写完成后,需要使用java提供的工具javac来执行才能真正的起作用。下面介绍一下javac工具相关注解的选项。

2.4.1、javac对注解处理支持

用法:javac

其中,注解可能乃至选项包括:

-cp 指定查找用户类文件和注释处理程序的位置。

-proc:{none,only} 控制是否执行注释处理和/或编译。-proc:none表示编译期不执行注解处理器; -proc:only表示只执行注解处理器,不进行任何注解之后的编译。

-processor [,,…]要运行的注释处理程序的名称;绕过默认的搜索进程。

-processorpath         指定查找注释处理程序的位置。如果未指定,将使用-cp指定的路径。

-d 指定存放生成的类文件的位置。

-s 指定存放生成的源文件的位置。

-Akey[=value] 传递给注释处理程序的选项。

2.4.2、执行编译

命令的执行目录为工程的根目录。执行前的目录结构:

编译注解处理器及注解程序。

命令:$ javac -d classes/ src/com/zenfery/example/annotation/proc/*.java src/com/zenfery/example/annotation/*.java

执行命令,生成GenerateInterface.class、CreateInterfaceProcessor.class,此时的目录结构如下:

执行注解处理器。命令:$ javac -cp classes/ -processor com.zenfery.example.annotation.proc.CreateInterfaceProcessor -d classes/ -s src/ src/com/zenfery/example/annotation/bean/*.java

标准输出日志:

可以看出,注解处理器循环执行了三次。第一次,对Teacher和Doctor类进行处理,并生成Teacher类对应的接口类TeacherIntSuffix;第二次,对第一次生成的类TeacherIntSuffix再做处理,这一次将不再产生新的类。第三次,未能发现新生成的类,执行结束。

此时目录结构如下:

生成了TeacherIntSuffix.java类,并进行了编译生成了TeacherIntSuffix.class。TeacherIntSuffix.java类如下:

后记:本节内容,在日常应用中使用的概率非常小,仅供理解。

Java注解 编译_Java注解(3)-注解处理器(编译期|RetentionPolicy.SOURCE)相关推荐

  1. java 注解开发_Java中的注解到底是如何工作的?

    作者:人晓 www.importnew.com/10294.html 自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Over ...

  2. android xml java混合编程_Java学习中注解与多线程,网络编程与XML技术

    本部分内容主要有集合框架及泛型,实用类,输入和输出处理,注解与多线程,网络编程与XML技术.初次学习这部分会感觉很难,主要是概念难于理解,最好是多看看例子,多练习.下面是个人的总结 拉勾IT课小编为大 ...

  3. java 注解作用_java 自定义的注解有什么作用

    展开全部 自定义注解,可以应用到反射中,比如自己32313133353236313431303231363533e59b9ee7ad9431333335333764写个小框架. 如实现实体类某些属性不 ...

  4. java eclipse 反编译_java的class文件反编译和Eclipse、MyEclipse反编译插件安装、使用...

    本帖最后由 pig2 于 2014-3-4 10:58 编辑 前言 我们在做项目中,可能经常需要看下别人写的源码,而别人提供的往往是jar文件,根本看不了,很影响开发效率.本人最近就为此而感到很不爽, ...

  5. java retentionpolicy_Java注解之如何利用RetentionPolicy.SOURCE生存周期

    上一篇文章简单讲了下Java注解的学习之元注解说明,学习了Java注解是如何定义的,怎么使用的,但是并没有介绍Java的注解是怎么起作用的,像Spring Boot里面的那些注解,到底是怎么让程序这样 ...

  6. Java 进阶巩固:什么是注解以及运行时注解的使用

    这篇文章 2016年12月13日星期二 就写完了,当时想着等写完另外一篇关于自定义注解的一起发.结果没想到这一等就是半年多 - -. 有时候的确是这样啊,总想着等条件更好了再干,等准备完全了再开始,结 ...

  7. 用自定义注解做点什么——自定义注解有什么用

    用自定义注解做点什么 前言 你不一定听过注解,但你一定对@Override不陌生. 当我们重写父类方法的时候我们就看到了@Override.我们知道它表示父类方法被子类重写了. 现在告诉你,@Over ...

  8. java编译时注解_Java注解处理器--编译时处理的注解

    1. 一些基本概念 在开始之前,我们需要声明一件重要的事情是:我们不是在讨论在运行时通过反射机制运行处理的注解,而是在讨论在编译时处理的注解. 注解处理器是 javac 自带的一个工具,用来在编译时期 ...

  9. Java注解 编译_Java注解处理器学习之编译时处理的注解详析

    1. 一些基本概念 在开始之前,我们需要声明一件重要的事情是:我们不是在讨论在运行时通过反射机制运行处理的注解,而是在讨论在编译时处理的注解. 编译时注解跟运行时注解到底区别在什么地方?其实说大也不大 ...

最新文章

  1. wireshark相关协议详解和nc命令建立对话
  2. 物联网产品背后潜藏着危机
  3. 加个属性让div成纵向横向无缝滚动(支持IE和FF)
  4. php+mysql投票代码_PHP+jQuery+MySql实现红蓝投票功能
  5. 阿里云的羊毛如何薅?创业者看过来!
  6. 天天早上慢跑一小时对身体好吗?
  7. (十一)OpenCV实现图像频率域滤波
  8. Codeforces Round #567 (Div. 2)
  9. npm的那些“坑”——持续更新
  10. 小程序毕设作品之微信小程序点餐系统毕业设计(4)开题报告
  11. 常用的Mysql数据库操作语句大全
  12. python 读写西门子PLC例子
  13. mysql复合索引加锁_Mysql加锁过程详解
  14. html中倒计时函数,关于倒计时的函数
  15. android的otg功能,android怎么打开otg功能
  16. Linux 创建无线热点
  17. TypeScript 学习笔记(四)--- 泛型(Generics)
  18. php json数据 转义,PHP JSON字符串,转义JS输出的双引号
  19. 个人信息管理系统数据表设计
  20. \t\t把超星图书虚拟打印为PDF格式,实现永久阅读

热门文章

  1. 买房前需要注意的事项有哪些
  2. flask的janja模板
  3. VUE3(setup响应式函数系统API)
  4. python基础其他(二十一)
  5. java集合的扩容研究
  6. asp.net应用程序无法连接oracle数据库,2020:ASP连接Oracle数据库问题的解决过程
  7. vue ui框架_Vue移动端UI框架指南
  8. gcc操作mysql 建表_用gcc批量建mysql库表
  9. 为啥我从后台查到的值在页面显示的是undefined_短说开发日报:2.7版本后台财务管理(11.19周四)...
  10. php 5.4.39 安装,Lamp 安装(CentOS6.6, php-5.4.39, httpd-2.4.12, mysql-5.6.24)