注解必须显式声明@Retention(RUNTIME)才能在运行时通过反射获取,否则method.getAnnotation()返回null;搭配@Target限定使用位置,二者缺一不可。

要让注解在正确的时间点可用,关键在于用好 @Retention —— 它直接决定注解“活到什么时候”,而不是靠猜测或默认值。
必须显式声明 @Retention(RUNTIME) 才能反射读取
多数业务场景(如 AOP 切面、权限校验、日志埋点)都需要在运行时通过反射获取注解。如果没写 @Retention,Java 默认用的是 RetentionPolicy.CLASS,此时注解虽保留在 .class 文件里,但 JVM 不加载进内存,method.getAnnotation(MyLog.class) 永远返回 null,且不报错、无提示。
- ✅ 正确写法:
@Retention(RetentionPolicy.RUNTIME) - ❌ 错误习惯:省略 @Retention,或误用 SOURCE/CLASS
- ⚠️ 注意:RUNTIME 带来反射开销,高频调用处需权衡缓存策略
按真实需求选生命周期,不是越长越好
生命周期不是“一律 RUNTIME”就万事大吉,得看谁在什么时候需要它:
- SOURCE:仅源码阶段有效,编译完即丢。适合构建期检查,比如禁止某方法被调用、生成 Builder 代码(Lombok 风格),零运行成本
- CLASS:存在于 .class 中,但反射不可见。适合字节码增强工具(如 ASM、ByteBuddy)在类加载前处理,框架内部常用,业务层少用
-
RUNTIME:唯一支持
getAnnotation()的选项,Spring、Hibernate、自定义切面都依赖它
搭配 @Target 才算真正规范
@Retention 管“活多久”,@Target 管“贴在哪”。两者缺一不可,否则注解行为不可控:
- 只设 @Retention(RUNTIME) 但没 @Target → 注解可被误标在字段、参数甚至包上,编译器不拦,运行时逻辑可能崩
- 只设 @Target(METHOD) 但没 @Retention(RUNTIME) → 编译通过,但反射拿不到,功能形同虚设
- ✅ 规范组合示例:
@Retention(RUNTIME) @Target(METHOD),明确限定“只允许标在方法上,且运行时可读”
其他元注解辅助生命周期理解与维护
@Documented 和 @Inherited 虽不改变生命周期,但影响注解是否“被看见”和“被延续”:
- @Documented:让注解出现在 Javadoc 中,调用方查文档就能知道“这个方法要加 @Retryable”
- @Inherited:仅对类级注解生效,子类自动继承父类的该注解(如统一审计开关),不适用于方法或字段
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











