当前位置: 首页 > Linux

什么是注解处理器

时间:2023-04-06 21:02:13 Linux

AnnotationProcessor初探平时的项目中有一个非常好用的插件叫lombok。它提供了一些简单的注解,可以用来生成javabean和一些getter/setter方法,提高了开发效率,节省了开发时间。今天我们就来看看lombok是用什么方法来实现这种操作的。其实lombok使用的是注解处理器,这是jdk1.5新增的特性。像@Getter只是一个注解,它真正的处理部分是在注解处理器中实现的。官方参考链接。背景介绍AnnotationProcessor其实全称为PluggableAnnotationProcessingAPI,一种插件式注解处理器。它是JSR269提案的实现。具体见链接中的内容,JSR269链接。它是如何工作的?可以参考下图:1.parseandenter:解析输入,java编译器在这个阶段会解析源码生成AST(抽象语法分析树)2.annotationprocessing:注解处理器阶段,此时,注释处理器将被调用。这时候可以校验代码,生成新文件等(处理完可以循环到第一步)3.analyseandgenerate:分析生成,这时候前两步之后是完成后,生成单词Section代码(现阶段理解糖,比如类型擦除)其实只是让你粗浅地了解它是如何执行的。练习看完以上资料,你的脑子里应该有个大概的印象了。下面我们写一个简单的例子来练习一下。使用注解处理器分两步:1.自定义一个注解2.继承AbstractProcessor并实现process方法。接下来我们写一个很简单的例子,就是在类中添加@InterfaceAnnotation,编译时生成一个“I”+类名的接口类。首先,我在这里定义了两个模块,一个用来写注解和处理器,一个用来调用注解。第一步:自定义一个注解@Target({ElementType.TYPE})@Retention(RetentionPolicy.SOURCE)public@interfaceInterfaceAnnotation{}1.@Target:表示这个注解用在什么上面,其中ElementType.TYPE是指使用2类上的这个注解。@Retention:表示保留多长时间什么阶段,其中RetentionPolicy.SOURCE是源码阶段,编译类上没有这个注解步骤2:继承AbstractProcessor,实现process方法@SupportedAnnotationTypes(value={"com.example.processor.InterfaceAnnotation"})@SupportedSourceVersion(value=SourceVersion.RELEASE_8)publicclassInterfaceProcessorextendsAbstractProcessor{@Overridepublicbooleanprocess(Setannotations,RoundEnvironmentroundEnv){MessagermessagerDi=processingEnv.getNOag。,"进入InterfaceProcessor~~~");//找出带有InterfaceProcessorSetclazz=roundEnv.getElementsAnnotatedWith(InterfaceAnnotation.class);clazz.forEach(item->{//生成一个接口类I+类名StringclassName=item.getSimpleName().toString();className="I"+className.substring(0,1)+className.substring(1);TypeSpectypeSpec=TypeSpec.interfaceBuilder(className).add修饰符(Modifier.PUBLIC).build();try{//生成java文件JavaFile.builder("com.example.processor",typeSpec).build().writeTo(newFile("./src/main/java/"));}catch(IOExceptione){e.printStackTrace();}});返回真;}}1.@SupportedAnnotationTypes:表示该处理器类应该生效哪些注解2.@SupportedSourceVersion:表示支持的java版本3.annotations:需要的注解是@SupportedAnnotationTypes对应的注解4.roundEnv:存储当前和上一轮处理环境信息的5.TypeSpec这个可能有点不清楚,它是javaPoet中的一个类,javaPoet是java生成java文件的第三方插件,所以这里用到这个类来生成java文件。其实也可以使用java自带的PrintWriter等输入输出流来生成java文件。,生成文件的方法有很多种。javaPoet的链接。使用javaPoet的指南。6.Messager是用来打印信息的,其实可以用System.out.println;7.如果process的返回为true,后面的注解处理器就不会再处理这个注解,如果为false,在下一轮处理中,其他注解处理器也会对这个注解进行处理和修改。写完之后需要指定处理器,META-INF/services/javax.annotation.processing.Processor写成com.example.processor.InterfaceProcessor。如果你不知道这是什么,可以看我的另一篇博客(实力宣传XD)什么是SPI?我们正在maven中编译注解处理器插件设置:org.apache.maven.pluginsmaven-compiler-plugin3.7.01.81.8-proc:none此时的目录结构如下:.├──HELP.md├──pom.xml├──processor.iml└──src└──main├──java│└──com│└──例子│└──处理器│├──InterfaceAnnotation.java│└──InterfaceProcessor.java└──资源└──META-INF└──服务└──javax.annotation.processing.Processor然后mvncleaninstall。第三步:在使用注解之前,如果编译了注解处理器,则引入注解处理器的jar包。在测试类中添加@InterfaceAnnotation@InterfaceAnnotationpublicclassTestProcessor{}maven指定编译期间使用的注解处理器。org.apache.maven.pluginsmaven-compiler-plugin3.7.01.81.8UTF-8com.example.processor.InterfaceProcessor此时,目录结构为.├──HELP.md├──pom.xml├──src│└──main│├──java││└──com││└──example││└──test││└──TestProcessor.java│└──resources└──test.iml再mvn编译,生成java文件,目录结构为:.├──HELP.md├──pom.xml├──src│└──main│├──java││└──com││└──example│││├──processor│││└──ITestProcessor.java//这里是生成的java文件││└──test││└──TestProcessor.java│└──resources├──target│├──classes││└──com││└──示例││└──测试││└──TestProcessor.class│├──生成源││└──注释│└──maven-status│└──maven-compiler-plugin│└──compile│└──default-compile│├──createdFiles.lst│└──inputFiles.lst└──test.iml看到生成的java文件就大功告成了~总结:1.java注解处理器可以用在很多地方,实际应用如lombok、Android生成片段等,只使用一个注解可以节省大量代码,提高效率;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...