java注解是结构化元数据而非装饰,其行为由元注解约束:@target限定位置,@retention控制生命周期(runtime必备),@documented决定javadoc可见性,@inherited仅对类级注解生效,@repeatable支持重复使用。

Java注解不是装饰,而是可被程序读取和响应的结构化元数据。真正驱动框架行为、实现声明式编程的核心,是元注解——它们定义了注解本身的行为边界与生命周期。
元注解的四大核心职责
所有自定义注解都必须由元注解约束,缺一不可:
- @Target:决定注解能贴在哪——类、方法、参数、字段、甚至类型参数(Java 8+)或包声明上。不加它,默认允许所有位置,极易引发误用。
- @Retention:决定注解活多久——SOURCE(编译即丢)、CLASS(进class但不进JVM)、RUNTIME(运行时可用)。Spring中@Autowired、@RequestMapping等必须设为RUNTIME,否则反射读不到。
- @Documented:决定是否出现在生成的Javadoc里。若你希望团队调用你的注解时能直接看到说明,就该加上它。
- @Inherited:仅对类级注解生效,表示子类自动继承父类所带的该注解。对方法、字段无效,这点常被误用。
@Repeatable:让同一位置支持多个同名注解
Java 8 引入的@Repeatable解决了早期“一个地方只能贴一个同名注解”的限制。但它不是独立存在,需配合容器注解使用:
- 先定义一个普通注解,如@Role,含String value();
- 再定义一个容器注解@Roles,其value()返回Role[]数组;
- 在@Role上标注@Repeatable(Roles.class)。
- 之后就能在类上写@Role("admin") @Role("user"),编译器会自动打包进@Roles。
运行时注解处理的关键细节
只有@Retention(RetentionPolicy.RUNTIME)的注解才能被反射读取,但读取过程有隐含规则:
- Class.getAnnotations() 返回所有直接声明的注解(不含继承);
- Class.getDeclaredAnnotations() 只返回本类显式声明的,不包含从父类继承的;
- Method.isAnnotationPresent(Class extends Annotation>) 是轻量判断方式,比getAnnotation()更高效;
- 若注解元素含枚举、Class、其他注解或数组类型,反射获取时需确保对应类型在类路径中已加载,否则抛TypeNotPresentException。
设计自定义注解的实用建议
好注解应像API一样清晰可靠:
- 命名用形容词或名词,如@Valid、@Loggable、@Transactional,避免动词形式;
- 必填项尽量少,多用default提供合理默认值;
- 元素类型优先选String、基本类型、Class、枚举,避免复杂嵌套;
- 若用于框架集成,务必明确指定@Target和@Retention,RUNTIME+METHOD是最常见组合;
- 搭配@Documented,让IDE提示和Javadoc同步可见,降低团队使用门槛。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











