Java注解本身是元数据,不参与运行;编译期通过@Retention(SOURCE)和AnnotationProcessor处理AST生成代码,运行期通过@Retention(RUNTIME)配合反射读取,但需注意生命周期、类加载器及语义约定。

Java 注解本身不参与运行,它们只是元数据;真正参与运行的是你写的 AnnotationProcessor(编译期)或通过反射读取注解的代码(运行期)。
注解怎么在编译期起作用:@Retention(RetentionPolicy.SOURCE) 和 AnnotationProcessor
这类注解只保留在源码阶段,比如 @Override、@SuppressWarnings。自定义时需配合 javax.annotation.processing.AbstractProcessor 实现编译期逻辑:
- 必须声明
@SupportedAnnotationTypes指定处理哪些注解 - 不能在 processor 里用反射读取被注解的类——此时字节码还没生成,只能用
Element和TypeMirrorAPI 分析 AST - 生成新文件要用
Filer.createSourceFile(),不能直接写磁盘 - Maven 中需用
maven-compiler-plugin配置annotationProcessors,否则 processor 不会被触发
注解怎么在运行期起作用:@Retention(RetentionPolicy.RUNTIME)
只有标了 @Retention(RetentionPolicy.RUNTIME) 的注解才能被反射读到。关键点在于:
-
Class.getAnnotation(Class)、Method.getAnnotation(Class)等方法返回的是代理对象,不是原始注解实例 - 注解接口的方法不能有参数、不能抛异常、不能有默认值以外的实现(即所有方法都必须有 default 值)
- 反射读取性能较低,频繁调用建议缓存结果,比如 Spring 就把
@RequestMapping解析结果存在HandlerMapping中 - 注意类加载器隔离问题:如果注解类由不同 ClassLoader 加载(如 OSGi 或某些容器),
isAnnotationPresent()可能返回 false,即使源码写了
常见踩坑:为什么我的注解“没生效”?
多数失效不是注解写错了,而是生命周期或使用方式不匹配:
立即学习“Java免费学习笔记(深入)”;
- 用了
@Retention(RetentionPolicy.CLASS)却试图用反射读取 → 改成RUNTIME - 自定义注解没加
@Target,导致 IDE 不报错但编译器忽略它(比如注在方法上却只允许类) - Spring 中
@Bean方法上的@Transactional不生效 → 因为是同一类内调用,代理未介入,得拆到另一个 bean - 用
javac -processor手动跑注解处理器时忘了加-s指定生成路径,导致找不到输出文件
最易被忽略的一点:注解的语义完全由使用者定义。Java 不管 @Deprecated 是否真废弃了,也不管 @Test 是否真执行了测试——这些行为全靠外部框架或工具链约定和实现。写注解容易,让别人(或自己半年后)准确理解并正确使用它,才是难点。










