一、注解的本质与生命周期
注解(@Annotation)是Java的元数据机制,核心生命周期由@Retention指定:
java
@Retention(RetentionPolicy.RUNTIME) // 生命周期:源码/字节码/运行时
@Target(ElementType.METHOD) // 作用目标:方法/类/字段等
public @interface Benchmark { }
- SOURCE:仅存于源码(如
@Override) - CLASS:编译至字节码(默认行为)
- RUNTIME:运行时可通过反射读取
二、编译时注解处理(APT)核心原理
处理流程:
javac → 调用注解处理器 → 生成新代码/资源 → 重新编译
关键组件:
AbstractProcessor:自定义处理器基类RoundEnvironment:提供当前轮次注解元素Filer:用于生成新源文件
图表
代码
三、实战:实现Builder模式生成器
1. 定义注解
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface AutoBuilder {}
2. 实现处理器
java
@SupportedAnnotationTypes("com.example.AutoBuilder")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class BuilderProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(annotation);
for (Element element : elements) {
if (element.getKind() == ElementKind.CLASS) {
generateBuilderClass((TypeElement) element);
}
}
}
return true;
}
private void generateBuilderClass(TypeElement classElement) {
String className = classElement.getSimpleName() + "Builder";
JavaFileObject builderFile = processingEnv.getFiler().createSourceFile(className);
try (PrintWriter out = new PrintWriter(builderFile.openWriter())) {
out.println("public class " + className + " {");
out.println(" private " + classElement + " instance = new " + classElement + "();");
// 生成builder方法...
out.println("}");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 注册处理器(META-INF/services)
创建文件:src/resources/META-INF/services/javax.annotation.processing.Processor
text
com.example.BuilderProcessor
4. 使用示例
java
@AutoBuilder
public class User {
private String name;
private int age;
// getters/setters...
}
// 编译后自动生成:
// public class UserBuilder { ... }
四、APT vs 运行时反射
|
特性 |
APT |
运行时反射 |
|
处理阶段 |
编译时 |
运行时 |
|
性能影响 |
零运行时开销 |
反射调用性能损耗 |
|
错误反馈 |
编译报错(即时定位) |
运行时异常(难追踪) |
|
代码生成能力 |
✅ 直接生成新源文件 |
❌ 仅能操作现有对象 |
|
典型应用 |
Lombok/MapStruct/Dagger |
Spring注解驱动 |
五、最佳实践与避坑指南
- 增量处理:实现
getSupportedOptions()声明-A参数,适配Gradle增量编译 - 避免循环:新生成的注解需在下一轮处理
- 调试技巧:使用
-XprintProcessorRounds输出APT处理日志 - IDE集成:在IntelliJ中启用
Enable annotation processing
关键提示:APT无法修改已有类,但可通过生成子类或辅助类实现增强(如Lombok的字节码操纵实际发生在编译后期)
1357

被折叠的 条评论
为什么被折叠?



