中 进阶
Java注解原理#
一句话答案#
注解是元数据标记,通过 @Retention 控制保留策略,运行时注解靠反射读取,编译时注解靠 APT 处理。
核心要点
注解的本质:
- 注解是元数据标记(
@interface定义),本身不包含业务逻辑 - 逻辑全靠处理器实现(反射处理 / APT 编译时处理)
四个核心元注解:
| 元注解 | 作用 | 常用值 |
|---|---|---|
@Retention | 注解保留策略 | SOURCE(编译丢弃)/ CLASS(字节码保留)/ RUNTIME(运行时可反射读取) |
@Target | 注解适用目标 | TYPE / METHOD / FIELD / PARAMETER 等 |
@Documented | 是否写入 Javadoc | — |
@Inherited | 子类是否继承父类的注解 | — |
两种处理方式:
运行时注解(RUNTIME):
→ 通过反射 getAnnotation() 读取注解信息
→ Spring 的 BeanPostProcessor 扫描 @Autowired/@Transactional 就是这种方式
编译时注解(SOURCE/CLASS):
→ 通过 APT(Annotation Processing Tool)在编译阶段生成代码
→ Lombok 的 @Data 就是编译时生成 getter/setter/toStringplaintext自定义注解三步走:
- 用
@interface定义注解,加上@Retention和@Target - 编写处理逻辑(反射读取或 APT 处理器)
- 在目标位置使用注解
面试回答(2分钟版)
Java注解本质上是一种元数据标记,它本身不包含任何业务逻辑,逻辑全靠处理器实现。注解通过@interface定义,用元注解控制行为:@Retention决定注解的生命周期——SOURCE级别编译后丢弃如@Override、CLASS级别保留到字节码但运行时不可见、RUNTIME级别运行时可通过反射读取,Spring的大部分注解都是RUNTIME级别;@Target指定注解能标注在哪里,比如方法、类或字段。运行时注解的处理靠反射:通过getAnnotation方法读取注解信息然后执行相应逻辑,Spring的BeanPostProcessor就是这样扫描@Autowired、@Transactional等注解并做处理的。编译时注解靠APT注解处理器在编译阶段生成代码,比如Lombok的@Data就是在编译时生成getter/setter/toString。自定义注解三步走:用@interface定义注解并加上元注解、编写处理逻辑(反射或APT)、在目标位置使用。关键要记住注解只是标记,真正干活的是处理器。
追问与易错
追问方向:
- “@Retention 三种策略的区别?”→ SOURCE 编译后丢弃(如 @Override);CLASS 保留到字节码但运行时不可见(默认值);RUNTIME 运行时通过反射可读取(Spring 注解均为此级别)
- “Spring 的注解是怎么生效的?”→ BeanPostProcessor 在 Bean 初始化前后通过反射扫描注解并执行相应逻辑,如 AutowiredAnnotationBeanPostProcessor 处理 @Autowired 注入
- “自定义注解怎么做?”→ 用 @interface 定义注解、加 @Retention 和 @Target 元注解指定生命周期和作用目标、编写处理器(反射读取或 APT 编译时处理)
易错点:
- ❌ “注解本身有逻辑”——注解只是标记,逻辑在处理器(反射/APT)中
- ❌ 混淆编译时注解和运行时注解的处理方式