设为retentionpolicy.class后反射无法获取注解,因为jvm不将其加载到运行时内存;必须改为runtime并重新编译注解类,否则任何运行时绕过方案均无效。

直接把注解的 @Retention 设成 RetentionPolicy.CLASS,就等于主动切断了运行时反射访问的通路——这不是“抓不到”,是根本没存下来。
为什么 CLASS 策略会让反射彻底失效
Java 注解有三档保留策略:
- SOURCE:只在源码阶段存在,编译后就丢掉;
- CLASS:保留在 .class 文件里,但 JVM 不加载进运行时内存,反射 API 完全不可见;
-
RUNTIME:不仅写进字节码,还会被 JVM 加载到元空间(Metaspace),
getAnnotation()才能查到。
所以设成 CLASS 后,哪怕你用 javap -v 能在字节码里看到注解信息,method.getAnnotation(MyAnn.class) 也一定返回 null——不是代码写错了,是 JVM 根本不给你读的机会。
必须改源码:把 RetentionPolicy.CLASS 换成 RUNTIME
这是唯一解,没有绕过方案。操作很简单,但容易忽略细节:
- 找到注解定义类,确认它用了
@Retention(RetentionPolicy.CLASS); - 改成
@Retention(RetentionPolicy.RUNTIME); - 确保同时有
@Target明确标注使用位置(比如ElementType.METHOD); - 重新编译该注解类,并确保所有依赖它的模块都重新编译或刷新 classpath。
注意:仅改调用方代码、加代理、换类加载器都无效——问题出在注解本身未进入运行时环境,不是反射路径或对象不对。
上线前快速验证是否生效
改完别急着打包,本地加个简单测试:
@MyAnnotation("test")
public void demoMethod() {}
<p>// 在单元测试或启动后执行:
Method m = this.getClass().getMethod("demoMethod");
System.out.println(m.getAnnotation(MyAnnotation.class)); // 必须打印出非 null 实例
</p>
如果还是 null,请检查:
- 是否改的是正确的注解类(尤其多模块项目,可能有同名注解);
- IDE 是否用了 stale 编译缓存(可尝试 Clean Project + Rebuild);
- Maven/Gradle 是否真正重新编译了该注解模块(mvn clean compile 最保险)。
如果注解来自第三方库,无法修改源码
那就只能换思路:
- 找该库是否有配套的
*Runtime版本注解(有些框架会提供两套); - 改用其他运行时可读的元数据方式,比如方法名约定、接口实现、配置文件映射;
- 若必须依赖该注解,可借助字节码处理工具(如 ASM)在构建期扫描并生成运行时可用的辅助类——但这已脱离标准反射范畴,属于定制化方案。
本质上,CLASS 是设计用来给编译器插件或构建工具消费的,不是给运行时反射用的。选错策略,就是用错了场合。











