java中注解能否在运行时被读取取决于@retention策略,只有runtime策略会使注解保留在jvm元空间并能被反射api获取;source和class策略下注解在运行时不可见。

Java中注解能否在运行时被读取,不取决于你写了多少反射代码,而取决于它有没有真正“住进”JVM内存——这由@Retention策略决定。RUNTIME是唯一能让注解进入元空间、被反射API触达的策略;SOURCE和CLASS阶段的注解,在类加载完成后就已“物理消失”,反射调用getAnnotation()必然返回null。
为什么只有 RUNTIME 注解能被反射读到
RUNTIME 策略会把注解字面量写入 .class 文件,并在类加载时一并载入 JVM 元空间(方法区),成为类元数据的一部分。此时 Class、Method、Field 等反射对象底层才有数据可查。
- SOURCE 注解:编译完就从内存里抹掉,
.class文件里根本不存在 - CLASS 注解:虽留在
.class文件中,但 JVM 不解析进运行时内存,反射 API 完全不可见 - RUNTIME 注解:随类元数据加载,全程对
isAnnotationPresent()和getAnnotation()开放
哪些场景必须用 RUNTIME
只要逻辑依赖运行时动态识别行为,就必须选 RUNTIME。这不是可选项,而是硬性前提。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 权限控制:如
@RequireRole("ADMIN"),拦截器需在每次请求时读取并校验 - 自动埋点或日志:如
@LogExecutionTime,AOP 在方法执行前后计时 - 参数校验:如
@NotNull,在 Controller 入参绑定前检查字段值 - 缓存与事务:如
@Cacheable或@Transactional,框架需在调用链中实时决策
别踩 CLASS 默认值的坑
没写 @Retention 的注解,默认是 CLASS 策略。表面看“编译通过、语法正确”,但一旦有人尝试反射读取,就会静默失败——getAnnotation() 永远为 null,功能彻底失活。
- 现象隐蔽:无编译错误、无运行异常,只有业务逻辑不生效
- 排查困难:容易误判为反射代码写错,实则根源在注解定义缺失保留策略
- 验证方法:用
javap -v YourClass.class查看字节码,搜索RuntimeVisibleAnnotations(有则为 RUNTIME)
读取 RUNTIME 注解的正确姿势
定义和使用必须闭环,漏掉任一环节都会导致读不到。
- 定义时显式声明
@Retention(RetentionPolicy.RUNTIME),不能省略也不能依赖默认 - 配合
@Target明确作用位置,比如@Target(ElementType.METHOD) - 反射获取时,先用
clazz.getDeclaredMethod("xxx")拿到目标Method对象 - 再调用
method.getAnnotation(YourAnno.class),返回非null才代表成功加载 - 拿到实例后,才可安全调用
anno.value()等属性驱动后续逻辑
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










