注解本质是继承Annotation的接口,非类也非语法糖;其生命周期由@Retention控制(SOURCE/CLASS/RUNTIME),处理依赖APT编译期生成或反射运行期解析,本身不执行逻辑,仅作为元数据标签供处理器驱动行为。

注解驱动开发不是“写个@就完事”,面试通关的关键是讲清三层逻辑:注解本身是什么、谁在什么时候读它、读完之后怎么用它。不能只背定义,要能画出从代码贴标签→编译器/反射识别→框架执行动作的完整链条。
注解本质不是类,而是带约束的接口
你写 @interface MyLog,编译后生成的是一个继承 java.lang.annotation.Annotation 的接口,不是类,也不能 new。JVM 运行时通过动态代理(AnnotationInvocationHandler)生成代理实例,所有属性值都来自常量池里的 memberValues Map。面试时如果被问“为什么注解不能有方法体”,直接答:它是接口,接口里只能有抽象方法(即注解元素),没有实现逻辑。
@Retention 是开关,选错就等于没写
很多自定义注解失效,根本原因就是忘了加 @Retention(RetentionPolicy.RUNTIME)。默认是 CLASS 级别,编译进 class 文件但运行时反射拿不到。必须明确三点:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- SOURCE:只给编译器看,比如 @Override,编译完就扔
- CLASS:存进字节码,但类加载时不进 JVM 方法区,APT 工具能扫到,反射不行
- RUNTIME:唯一能让 getAnnotation() 拿到的级别,Spring、MyBatis 全靠它
注解不干活,干活的是处理器
注解自己没有行为,真正起作用的是两套处理机制:
立即学习“Java免费学习笔记(深入)”;
- 编译期处理:写 AbstractProcessor 子类,配合 @SupportedAnnotationTypes,在 javac 阶段扫描并生成新代码。Lombok 的 @Data、ButterKnife 的 @BindView 都走这条路
- 运行期处理:用反射获取注解元数据,再做判断和调用。比如 Spring 启动时扫描 @Controller,把类注册进容器;AOP 拦截器检查方法是否有 @Transactional,决定是否开启事务
元注解是说明书,不是功能开关
@Target、@Retention、@Documented、@Inherited 这四个不是让你“加功能”的,是告诉编译器和 JVM:“这个注解允许贴在哪”“保留到什么时候”“要不要出现在文档里”。举例:
- @Target(ElementType.METHOD) 表示只能加在方法上,加在类上直接编译报错
- @Inherited 只对类注解生效,子类自动继承父类的该注解;方法或字段上的注解不会被继承
- @Documented 决定 Javadoc 生成时是否把该注解显示出来,和功能无关


















