要让子类通过class.getannotation()获取父类注解,关键在于注解本身必须同时满足:@inherited修饰、@target(elementtype.type)、@retention(retentionpolicy.runtime),且子类不能显式声明同名注解。

要让子类能通过 Class.getAnnotation() 拿到父类上的注解,关键不是“怎么处理缺失”,而是“必须提前定义好可继承的注解”——@Inherited 是元注解,只能在自定义注解声明时加,不能事后补救。
确认注解本身是否满足继承三要素
子类识别不到父类注解,大概率是因为该注解没同时满足以下三个条件:
-
@Inherited:注解自身必须显式用
@Inherited修饰 - @Target(ElementType.TYPE):只能标注在类、接口、枚举上;若还允许 METHOD 或 FIELD,就失去继承能力
-
@Retention(RetentionPolicy.RUNTIME):必须运行时可见;
CLASS或SOURCE级别下反射根本读不到
子类未显式重复声明同名注解
@Inherited 的生效前提是:子类类声明上没有自己写一遍这个注解。一旦写了,就会完全屏蔽父类的,反射只返回子类自己的实例。
例如:
✅ 有效(子类无声明):@MyConfig("parent") class Parent {}class Child extends Parent {} → Child.class.getAnnotation(MyConfig.class) 返回非 null❌ 失效(子类显式覆盖):
@MyConfig("child") class Child extends Parent {} → 只能拿到 @MyConfig("child"),父类注解不可见
替代方案:手动向上遍历继承链
如果已有注解无法修改(比如第三方库注解没加 @Inherited),或需要兼容多层继承/接口场景,就得绕过 @Inherited 机制,自己查:
- 从子类开始,调用
clazz.getAnnotation(MyAnno.class) - 为空则继续
clazz = clazz.getSuperclass(),直到为null - 可扩展支持接口:
clazz.getInterfaces(),按需设定优先级(如本类 > 父类 > 接口)
这种模式不依赖元注解,稳定可控,Spring 的 MergedAnnotations 就是这样实现的。
警惕常见误用场景
以下情况 @Inherited 压根不工作,不用尝试修复:
- 注解标在方法或字段上(哪怕加了
@Inherited,子类重写方法也拿不到) - 父类是通过接口实现间接获得注解(如被
@Service标记,而@Service自身没加@Inherited) - 使用 Spring AOP 代理后调用
getClass(),拿到的是代理类而非原始类(需用AopProxyUtils.ultimateTargetClass(proxy))










