摘要:注解处理器初探平时做项目中有个非常好用的一个插件叫它提供了一些简单的注解可以用来生成和一些方法提高了开发的效率节省了开发时间今天我们就来看看使用的什么方式来实现这种操作的其实使用的是这个是中增加的新功能像只是一个注解它真正的处理部分是在注解
注解处理器初探
平时做项目中有个非常好用的一个插件,叫lombok.它提供了一些简单的注解,可以用来生成javabean和一些getter/setter方法,提高了开发的效率节省了开发时间.
今天我们就来看看lombok使用的什么方式来实现这种操作的.其实lombok使用的是annotation processor,这个是jdk1.5中增加的新功能.像@Getter只是一个注解,它真正的处理部分
是在注解处理器里面实现的.官方参考链接.
注解处理器其实全称叫Pluggable Annotation Processing API,插入式注解处理器,它是对JSR269提案的实现,具体可以看链接里面的内容,JSR269链接.
它是怎么工作的呢?可以参考下图:
1.parse and enter:解析和输入,java编译器这个阶段会把源代码解析生成AST(抽象语法分析树)
2.annotation processing:注解处理器阶段,此时将调用注解处理器,这时候可以校验代码,生成新文件等等(处理完可以循环到第一步)
3.analyse and generate:分析和生成,此时前两步完成后,生成字节码(这个阶段进行了解糖,比如类型擦除)
这些其实只是为了给大家留有一个粗浅的印象,它是怎么执行的.
看了上面的资料,大脑中应该有了一个大概的印象,现在我们实际操作一下写一个简单的例子,实践一下.
要使用注解处理器需要两个步骤:
1.自定义一个注解
2.继承AbstractProcessor并且实现process方法
我们接下来写一个很简单的例子,就是在一个类上加上@InterfaceAnnotation,编译的时候去生成一个"I"+类名的接口类.
首先我这里是定义了两个moudle,一个用来写注解和处理器,另一个用来调用注解.
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface InterfaceAnnotation { }
1.@Target:表示的是这个注解在什么上面使用,这里ElementType.TYPE是指在类上使用该注解
2.@Retention:表示的是保留到什么阶段,这里RetentionPolicy.SOURCE是源代码阶段,编译后的class上就没有这个注解了
@SupportedAnnotationTypes(value = {"com.example.processor.InterfaceAnnotation"}) @SupportedSourceVersion(value = SourceVersion.RELEASE_8) public class InterfaceProcessor extends AbstractProcessor { @Override public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) { Messager messager = processingEnv.getMessager(); messager.printMessage(Diagnostic.Kind.NOTE, "进入到InterfaceProcessor中了~~~"); // 将带有InterfaceProcessor的类给找出来 Set extends Element> clazz = roundEnv.getElementsAnnotatedWith(InterfaceAnnotation.class); clazz.forEach(item -> { // 生成一个 I + 类名的接口类 String className = item.getSimpleName().toString(); className = "I" + className.substring(0, 1) + className.substring(1); TypeSpec typeSpec = TypeSpec.interfaceBuilder(className).addModifiers(Modifier.PUBLIC).build(); try { // 生成java文件 JavaFile.builder("com.example.processor", typeSpec).build().writeTo(new File("./src/main/java/")); } catch (IOException e) { e.printStackTrace(); } }); return true; } }
1.@SupportedAnnotationTypes:表示这个processor类要对什么注解生效
2.@SupportedSourceVersion:表示支持的java版本
3.annotations:被要求的注解,就是@SupportedAnnotationTypes对应的注解
4.roundEnv:存放着当前和上一轮processing的环境信息
5.TypeSpec这个可能有点没看懂是干嘛的,它是javaPoet中的一个类,javaPoet是java用于生成java文件的一款第三方插件很好用,所以这里使用了这个类来生成java文件,
实际上这里用java自带的PrintWriter等输入输出流也可以生成java文件,生成文件有很多方式.javaPoet的链接.javaPoet使用指南.
6.Messager是用来打印输出信息的,System.out.println其实也可以;
7.process如果返回是true后续的注解处理器就不会再处理这个注解,如果是false,在下一轮processing中,其他注解处理器也会来处理改注解.
写好之后,这里需要指定processor,META-INF/services/javax.annotation.processing.Processor 写好com.example.processor.InterfaceProcessor.如果你不知道这是啥,可以看下我另一篇博客(实力推广XD)什么是SPI
我们在把注解处理器给编译好,maven里插件的设置:
org.apache.maven.plugins maven-compiler-plugin 3.7.0 1.8 -proc:none
此时的目录结构是这样:
. ├── HELP.md ├── pom.xml ├── processor.iml └── src └── main ├── java │ └── com │ └── example │ └── processor │ ├── InterfaceAnnotation.java │ └── InterfaceProcessor.java └── resources └── META-INF └── services └── javax.annotation.processing.Processor
然后mvn clean install.
第三步:使用注解在使用之前呢,注解处理器要是编译好的.引入注解处理器的jar包.
测试类加上@InterfaceAnnotation
@InterfaceAnnotation public class TestProcessor { }
maven指定编译时使用的注解处理器.
org.apache.maven.plugins maven-compiler-plugin 3.7.0 1.8 UTF-8 com.example.processor.InterfaceProcessor
此时目录结构是
. ├── HELP.md ├── pom.xml ├── src │ └── main │ ├── java │ │ └── com │ │ └── example │ │ └── test │ │ └── TestProcessor.java │ └── resources └── test.iml
然后mvn compile,生成了java文件,此时目录结构是:
. ├── HELP.md ├── pom.xml ├── src │ └── main │ ├── java │ │ └── com │ │ └── example │ │ ├── processor │ │ │ └── ITestProcessor.java // 这里就是生成的java文件 │ │ └── test │ │ └── TestProcessor.java │ └── resources ├── target │ ├── classes │ │ └── com │ │ └── example │ │ └── test │ │ └── TestProcessor.class │ ├── generated-sources │ │ └── annotations │ └── maven-status │ └── maven-compiler-plugin │ └── compile │ └── default-compile │ ├── createdFiles.lst │ └── inputFiles.lst └── test.iml
看到了生成的java文件就大功告成~
总结:1.java注解处理器在很多地方都可以使用,实际应用比如lombok,安卓生成fragment等等,只使用一个注解可以省去很多代码,提高效率;
2.本文只是列举了一个很简单的例子,很多注解处理器里面的api都没有使用到,读者有兴趣的可以自行研究,而且有涉及到抽象语法树的api;
3.注解处理器可以用于生成新的类来完成某些功能,但是不能直接修改当前的类.
1.https://docs.oracle.com/javas...
2.https://jcp.org/aboutJava/com...
3.https://github.com/square/jav...
4.https://www.cnblogs.com/throw...
5.http://notatube.blogspot.com/...
6.https://www.baeldung.com/java...
7.http://hannesdorfmann.com/ann...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/75347.html
摘要:虚拟主机管理系统,是干嘛的虚拟主机管理系统是一款管理软件,它可以实现对虚拟主机,操作系统的服务器等进行再次设置,一般来说是服务商用来管理域名,虚拟主机,数据库,还有企业邮箱等的一个网站平台。同时虚拟主机管理系统还包含了财务管理功能功能。虚拟主机管理系统,是干嘛的?虚拟主机管理系统是一款管理软件,它可以实现对虚拟主机,操作系统的服务器等进行再次设置,一般来说是IDC服务商用来管理域名,虚拟主机...
摘要:同时虚拟主机管理系统还包含了财务管理功能功能。随着互联网的发展和技术的不断更新,虚拟主机管理系统的开发也越来越完善,功能也越来越强大,尤其值得一说的是虚拟主机管理系统更加智能化。点开网页出现虚拟主机已开通是什么意思?虚拟主机是把一台服务器分成很多虚拟的服务器,每一个虚拟主机都具有独立的域名和完整的Internet服务器(支持WWW、FTP、E-mail等)功能。缺点只有一个id,一旦有别的网...
摘要:先来看代码吧,一会松哥再慢慢解释关于这一段自动配置,解释如下首先注解表明这是一个配置类。本文的案例,松哥已经上传到上了,地址。我们使用 Spring Boot,基本上都是沉醉在它 Stater 的方便之中。Starter 为我们带来了众多的自动化配置,有了这些自动化配置,我们可以不费吹灰之力就能搭建一个生产级开发环境,有的小伙伴会觉得这个 Starter 好神奇呀!其实 Starter 也都...
摘要:为何有查阅了的文档,并没有找到字段的定义,直到才知道它是中最早就提出的概念。况且目前大部分仍是采用,所以便使用了另一个字段。所以目前主流的打包工具都是支持的,鉴于其优点,字段很有可能加入的规范之中。 引入 最近团队的一个同学在搞 npm library 源码的调试插件,因为内部的一个组件库含有大量的逻辑,在某个项目中不经意就出现一个磨人的 bug,但是组件库发布都是打包编译后的代码,而...
阅读 1407·2021-09-23 11:21
阅读 3104·2019-08-30 14:14
阅读 3186·2019-08-30 13:56
阅读 4134·2019-08-30 11:20
阅读 1948·2019-08-29 17:23
阅读 2763·2019-08-29 16:14
阅读 1692·2019-08-28 18:18
阅读 1489·2019-08-26 12:14