注解处理器是干嘛的

简介: 注解处理器是干嘛的

注解处理器初探

    平时做项目中有个非常好用的一个插件,叫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上就没有这个注解了

第二步:继承AbstractProcessor并且实现process方法

@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里插件的设置:

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.7.0</version>
        <configuration>
              <source>1.8</source>
              <target>1.8</target>
              <!-- 不加这一句编译会报找不到processor的异常-->
              <compilerArgument>-proc:none</compilerArgument>
        </configuration>
</plugin>

此时的目录结构是这样:

.
├── 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指定编译时使用的注解处理器.

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.7.0</version>
        <configuration>
              <source>1.8</source>
              <target>1.8</target>
              <encoding>UTF-8</encoding>
              <annotationProcessors>
                  <annotationProcessor>
                        com.example.processor.InterfaceProcessor
                  </annotationProcessor>
              </annotationProcessors>
        </configuration>
</plugin>

此时目录结构是

.
├── 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/javase/8/docs/api/javax/annotation/processing/Processor.html
2.https://jcp.org/aboutJava/communityprocess/final/jsr269/index.html
3.https://github.com/square/javapoet
4.https://www.cnblogs.com/throwable/p/9139908.html
5.http://notatube.blogspot.com/2010/11/project-lombok-trick-explained.html(介绍处理过程)
6.https://www.baeldung.com/java-annotation-processing-builder
7.http://hannesdorfmann.com/annotation-processing/annotationprocessing101

相关文章
|
8月前
|
人工智能 自然语言处理 搜索推荐
2026打工人必备偷懒工具:OpenClaw(Clawdbot)阿里云极速部署+5大高效AI工作流分享
在AI工具遍地的今天,很多人手里握着OpenClaw这样的“数字员工”,却只把它当普通搜索引擎使用,浪费了其强大的自动化能力。其实,OpenClaw的核心价值在于通过简单提示词搭建专属工作流,让AI替你处理开会准备、定期复盘、学习成长、副业创作等重复工作,让效率提升5倍以上。
1471 131
|
Java Android开发
jvisualvm分析jvm内存溢出
jvisualvm分析jvm内存溢出
2124 0
jvisualvm分析jvm内存溢出
|
负载均衡 NoSQL Java
redis中的io多线程(线程池)
redis中的io多线程(线程池)
912 0
|
4月前
|
存储 人工智能 自然语言处理
拒绝“大模型幻觉”:一文彻底搞懂 RAG(检索增强生成)技术全流程
本文深入解析RAG(检索增强生成)技术,直击大模型落地私有知识场景的核心痛点——如何让LLM精准、低成本、高时效地基于企业文档作答。从文本分片、向量化索引,到召回重排、增强生成,系统拆解五大关键步骤,揭示RAG作为“AI外挂”的底层逻辑与工程实践精髓。
拒绝“大模型幻觉”:一文彻底搞懂 RAG(检索增强生成)技术全流程
|
9月前
|
运维 Cloud Native 安全
服务网格别急着上:Istio、Linkerd、Envoy,我都用过,说点大实话
服务网格别急着上:Istio、Linkerd、Envoy,我都用过,说点大实话
494 1
|
8月前
|
人工智能 JavaScript 数据可视化
保姆级教程:OpenClaw(Clawdbot)阿里云及Windows本地部署方案,与本地Ollama配置指南
在AI智能体快速普及的2026年,OpenClaw(前身为Clawdbot)凭借开源免费、可自托管、系统级权限控制的核心优势,成为个人与轻量团队打造专属AI助手的首选工具,其GitHub星标已飙升至18万+,登顶多个开源榜单。Ollama作为目前最受开发者欢迎的本地大模型运行工具,GitHub星标突破16万,支持480+开源模型一键部署,二者组合可实现“本地推理+本地执行”的全闭环,彻底摆脱对云端大模型的依赖,确保数据隐私安全且无网络依赖。
4707 2
|
11月前
|
存储 监控 Shell
四、Portainer图形化管理实战与Docker镜像原理
如果觉得命令行繁琐,可以试试Portainer这个图形化管理工具,让你在网页上点点鼠标就能轻松管理容器和镜像。安装它只需要一条docker run命令,非常方便。 同时,要理解Docker为何如此高效,关键在于它的镜像原理:镜像像洋-葱一样分层,启动容器时只在外面加一层可写的“外皮”。所有改动都发生在这层“外皮”上,这就是容器启动快、占用空间小的秘诀。
1229 5
|
8月前
|
数据采集 机器学习/深度学习 人工智能
全球Top下载中文开源数据集更新|OpenCSG持续打造中文高质量数据集开源底座
OpenCSG正式发布Fineweb-Edu-Chinese V2.2数据集:覆盖预训练(1.5T tokens,质量分层)与SFT微调(143.7万条DeepSeek V3.2蒸馏问答对)全流程,严格事实锚定、支持溯源,是当前少有的高质量中文教育全栈数据解决方案。
734 13
|
人工智能 运维 API
Dify开发者必看:如何破解MCP集成与Prompt迭代难题?
Dify 是一个面向AI时代的开源大语言模型(LLM)应用开发平台,致力于让复杂的人工智能应用构建变得简单高效,目前已在全球范围内形成显著影响力,其 GitHub 仓库 Star 数截至 2025 年 6 月已突破 100,000+,目前,Dify 已经成为 LLMOps 领域增长最快的开源项目之一。
|
人工智能 监控 Java
Spring AI Alibaba实践|后台定时Agent
基于Spring AI Alibaba框架,可构建自主运行的AI Agent,突破传统Chat模式限制,支持定时任务、事件响应与人工协同,实现数据采集、分析到决策的自动化闭环,提升企业智能化效率。
Spring AI Alibaba实践|后台定时Agent