Java 注解处理器(APT)实战:手把手教你自定义编译时注解生成代码
·
Java 注解处理器(APT)实战:自定义编译时注解生成代码
1. 注解处理器核心概念
- APT(Annotation Processing Tool):Java 编译时处理注解的工具,在源码编译阶段扫描并处理注解。
- 核心优势:零运行时开销,生成的代码直接参与编译。
- 典型应用:Lombok、ButterKnife、Dagger 等框架。
2. 实战步骤
2.1 创建自定义注解
// 定义编译时注解
@Retention(RetentionPolicy.SOURCE) // 仅保留在源码阶段
@Target(ElementType.TYPE) // 作用于类
public @interface AutoBuilder {
}
2.2 实现注解处理器
@AutoService(Processor.class) // Google AutoService 自动注册
@SupportedAnnotationTypes("com.example.AutoBuilder") // 处理的注解
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class BuilderProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// 遍历所有被 @AutoBuilder 标记的类
for (Element element : roundEnv.getElementsAnnotatedWith(AutoBuilder.class)) {
if (element.getKind() == ElementKind.CLASS) {
TypeElement classElement = (TypeElement) element;
// 生成 Builder 类
generateBuilderClass(classElement);
}
}
return true;
}
private void generateBuilderClass(TypeElement classElement) {
String className = classElement.getSimpleName() + "Builder";
String packageName = processingEnv.getElementUtils()
.getPackageOf(classElement).toString();
try {
// 创建新的 Java 源文件
JavaFileObject builderFile = processingEnv.getFiler()
.createSourceFile(packageName + "." + className);
try (PrintWriter writer = new PrintWriter(builderFile.openWriter())) {
// 生成 Builder 类代码
writer.println("package " + packageName + ";");
writer.println("public class " + className + " {");
writer.println(" private final " + classElement.getSimpleName() + " target;");
writer.println(" public " + className + "() { this.target = new " + classElement.getSimpleName() + "(); }");
// 为每个字段生成 setter 方法
for (Element field : classElement.getEnclosedElements()) {
if (field.getKind() == ElementKind.FIELD) {
String fieldName = field.getSimpleName().toString();
String fieldType = field.asType().toString();
writer.println(" public " + className + " " + fieldName + "(" + fieldType + " value) {");
writer.println(" target." + fieldName + " = value;");
writer.println(" return this;");
writer.println(" }");
}
}
writer.println(" public " + classElement.getSimpleName() + " build() { return target; }");
writer.println("}");
}
} catch (IOException e) {
throw new RuntimeException("生成 Builder 失败: " + e);
}
}
}
2.3 配置依赖 (Maven)
<dependencies>
<!-- 注解处理器依赖 -->
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId> <!-- 可选:更优雅的代码生成 -->
<version>1.13.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 编译时启用注解处理 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.0.1</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
3. 使用示例
// 应用自定义注解
@AutoBuilder
public class User {
String name;
int age;
}
// 编译后自动生成 UserBuilder 类
User user = new UserBuilder()
.name("Alice")
.age(30)
.build();
4. 关键机制解析
| 组件 | 作用 | 重要方法 |
|---|---|---|
AbstractProcessor |
处理器基类 | process() |
ProcessingEnvironment |
处理环境 | getFiler() (文件操作) |
RoundEnvironment |
扫描上下文 | getElementsAnnotatedWith() |
Filer |
代码生成器 | createSourceFile() |
5. 调试技巧
- 启用编译日志:
mvn clean compile -X - 查看生成代码:
在target/generated-sources/annotations目录下检查生成的.java文件 - 错误处理:
使用processingEnv.getMessager().printMessage()输出诊断信息
6. 高级场景
- 代码优化:使用 JavaPoet 替代手动拼接代码
- 多轮处理:通过
RoundEnvironment.processingOver()判断处理轮次 - 元注解处理:结合
@SupportedAnnotationTypes("*")实现全局扫描
注意事项:
- 注解处理器不能修改已有代码,只能生成新文件
- 处理器需独立模块或指定
annotationProcessorPath- 避免循环依赖(如处理器不能依赖自身生成的代码)
通过此实战教程,您可快速掌握 APT 的核心开发流程,实现高效的编译时代码生成,大幅提升项目可维护性。
更多推荐
所有评论(0)