Java注解是元数据,本身不执行逻辑;编译期由AnnotationProcessor处理(需实现Processor接口并注册),运行时需@Retention(RUNTIME)配合反射读取,@Target和@Retention决定使用范围与生命周期。

Java 注解本身不执行任何逻辑,它只是元数据;真正起作用的是读取注解的代码——可能是编译期处理器(AnnotationProcessor)、运行时反射(getAnnotations())或 JVM 内置机制(如 @Override)。
注解在编译期被处理:AnnotationProcessor 是怎么介入的
当你写 @Entity 或自定义 @Route,且希望生成代码或校验结构,就得靠编译期注解处理器。它不是运行时加载的类,而是在 javac 执行过程中被调用的独立组件。
- 必须实现
javax.annotation.processing.Processor接口,并通过META-INF/services/javax.annotation.processing.Processor声明 - 不能依赖运行时类路径——处理器运行在编译器上下文中,
ClassLoader.getSystemClassLoader()不可用 - 处理的是
Element(如TypeElement、VariableElement),不是反射对象;无法调用方法或获取运行时值 - 常见错误:
error: cannot find symbol,往往因为处理器未正确注册,或依赖了尚未编译完成的模块
运行时注解怎么读取:反射 + RetentionPolicy.RUNTIME
只有声明为 @Retention(RetentionPolicy.RUNTIME) 的注解才能通过反射拿到。JVM 不会自动解析它们,你得自己写逻辑去检查、判断、响应。
-
Class.getAnnotation(Class)只查本类声明,不包含继承的;要用getDeclaredAnnotation()查显式声明,isAnnotationPresent()更轻量 - 字段/方法上的注解需先获取对应
Field或Method对象,再调用其getAnnotation() - 性能敏感场景慎用:频繁反射 + 注解扫描会触发类加载和元数据解析,可考虑缓存
Annotation实例,而非每次重新获取 - 注意默认值陷阱:
@interface中定义的String value() default "abc",若未显式赋值,反射返回的就是这个默认值,不是null
@Target 和 @Retention 决定注解“能写在哪”和“能活到哪”
这两个元注解直接约束注解的使用边界和生命周期,写错会导致编译失败或运行时完全不可见。
立即学习“Java免费学习笔记(深入)”;
-
@Target({ElementType.METHOD, ElementType.TYPE})表示只能标在方法或类上;标在字段上会报error: annotation is not applicable to this kind of declaration -
@Retention(RetentionPolicy.SOURCE)注解只存在于源码中,连.class文件里都没有,javap反编译也看不到 -
@Retention(RetentionPolicy.CLASS)会进字节码但不进 JVM 方法区,运行时getAnnotation()返回null,但字节码工具(如 ASM)能扫描到 - 误设
@Retention(RetentionPolicy.CLASS)却想用反射读取,是线上排查不到注解行为的最常见原因
注解真正的复杂点不在定义,而在谁读、何时读、怎么读——同一套注解,编译期处理和运行时反射的约束完全不同,混用或假设“写了就能被看到”,几乎必然出问题。










