注解是编译期写入字节码的元数据,本身不执行逻辑,真正生效依赖处理器;需掌握Spring类注解、自定义运行时注解、编译期APT三类用法,并理解从源码→字节码→JVM加载→反射获取的完整链路。

注解不是背概念就能答好的知识点,面试官真正想看的是你能不能说清“它在哪用、为什么这么用、底层怎么跑起来”。学注解,得从运行时行为反推设计逻辑,而不是死记元注解列表。
先搞懂注解到底是什么
别一上来就背 @Target @Retention。先记住一句本质:注解是编译期写进字节码的元数据,本身不执行任何逻辑;真正干活的是读取它的处理器(比如反射代码、APT 工具或 Spring 的 BeanPostProcessor)。
你可以把它理解成“贴在代码上的标签”,标签本身没动作,但有人会定期巡查这些标签并按规则做事。
重点掌握三类注解的典型用法
面试高频场景就这三块,每类都要能说出“谁在用、怎么触发、关键代码在哪”:
- Spring 类注解:如 @Controller、@Service、@Transactional。它们靠 Spring 的扫描机制(ClassPathBeanDefinitionScanner)+ 后置处理器(ConfigurationClassPostProcessor)解析,最终注册为 Bean 或织入代理。
- 自定义运行时注解:比如 @Log、@Validate。必须带 @Retention(RetentionPolicy.RUNTIME),然后用反射(Method.getAnnotation())在切面或拦截器里读取,再决定是否执行日志、校验等动作。
- 编译期注解(APT):如 ButterKnife 的 @BindView、Lombok 的 @Data。这类不靠反射,而是在 javac 编译阶段通过 AbstractProcessor 生成额外 Java 文件,运行时零开销——这也是它和运行时注解的根本区别。
动手写一个可落地的自定义注解
光看不行,写一遍才能建立真实认知。建议按这个最小闭环练:
立即学习“Java免费学习笔记(深入)”;
- 定义注解:用 @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME)
- 写个 AOP 切面:用 @Around 拦截被该注解标记的方法
- 在切面里用 reflection 获取注解属性,比如是否开启、超时时间等
- 加点实际逻辑:方法耗时超过阈值就打 warn 日志,或自动重试一次
跑通后,再把日志换成发告警、把重试换成降级,你就自然理解框架里“注解驱动行为”的设计思想了。
面试常问的底层问题要能讲清链路
被问到“注解是怎么生效的”,不能只答“用了反射”。得把链条说完整:
- 源码里写了 @MyAnno,编译后 class 文件里多了 Annotation 属性表
- JVM 加载类时,把这些元数据放进内存(运行时常量池或类结构体)
- 你的代码调用 method.getAnnotation(MyAnno.class),触发 JVM 提供的反射 API 去查这个结构
- 查到后返回一个动态代理对象(实现了 MyAnno 接口),调用 value() 实际走的是代理的 invoke 方法
这一串下来,才算真正踩过坑、理过线,而不是照着笔记念。


















