@Inherited仅对类继承有效:子类通过getAnnotations()可继承父类上被@Inherited修饰且@Retention(RUNTIME)的类注解;对接口、方法、字段、参数等无效,也不适用于接口实现关系。

@Inherited 只对类的继承关系起作用,对接口和实现类之间完全无效——这不是 bug,而是 Java 语言规范明确设计的行为。
核心限制:@Inherited 不处理接口实现
Java 官方文档写得非常清楚:“this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect”。也就是说:
- 即使你在接口上定义了一个带 @Inherited 的注解,并在接口上标注了它,实现类不会自动获得该注解
- JVM 反射调用
getAnnotation()时,根本不会检查所实现的接口,哪怕接口上有同名、同配置的注解 - 接口是“契约”,不是“父类”,而 @Inherited 的语义只存在于
extends关系中,不适用于implements
@Inherited 对方法、字段、参数注解一律无效
它只影响 @Target(ElementType.TYPE) 类型的注解,且仅当该注解被用于类(class)声明时才可能被子类继承:
- 父类方法上的 @Inherited 注解 → 子类重写后不会自动携带
- 接口方法上标注的自定义注解(如 @Log)→ 实现类方法不会继承,Spring AOP 也无法直接拦截
- 字段、构造器、参数等位置的注解 → 即使加了 @Inherited,也完全不起作用
Spring 场景下常见误判点
很多开发者以为“接口加了注解,实现类没生效是框架问题”,其实根源在反射机制本身:
- 使用 JDK 动态代理时,
joinPoint.getTarget().getClass()返回的是$ProxyXX,它不是实现类,也不保留接口方法上的注解信息 - Spring Framework 4.x 默认无法读取接口方法上的 RUNTIME 注解;5.x 起才增强支持,但前提是调用方式正确(如用
Advised或AopProxyUtils.ultimateTargetClass()找原始类) - 即使你给注解加了 @Inherited,只要它的
@Target不含ElementType.TYPE,或@Retention不是RUNTIME,它就不可能被继承或反射获取
替代方案建议
如果目标是让实现类“感知”接口的元信息,不能依赖 @Inherited,而应采用显式设计:
- 在实现类上手动重复标注相同注解(最直接,适合少量实现)
- 通过
clazz.getInterfaces()主动遍历接口,再调用interface.getDeclaredMethod(...).getAnnotation(...)获取接口方法注解(需注意 Spring 版本兼容性) - 改用抽象基类代替接口,把注解放在抽象类上,并确保注解满足 @Inherited + @Target(TYPE) + @Retention(RUNTIME)
- 在 Spring AOP 切面中,用
AopProxyUtils.ultimateTargetClass(proxy)获取真实类,再结合接口反射做联合判断

















