| 策略 | 保留範圍 | 類文件中是否存在 | 運行時可否反射獲取 | 典型用途 |
|---|---|---|---|---|
| RetentionPolicy.SOURCE | 僅源碼階段 | 否 (編譯器丟棄) | 否 | 編譯時檢查、生成代碼、文檔生成 |
| RetentionPolicy.CLASS | 編譯至類文件 | 是 | 否 (JVM 加載時丟棄) | 字節碼分析、註解處理器 (APT)、框架構建元數據 |
| RetentionPolicy.RUNTIME | 運行時期 | 是 | 是 | 依賴注入、ORM 映射、Web 路由、參數驗證、動態代理 |
特點:註解只存在於 .java 文件,javac 編譯時不寫入 .class。
核心用途:
@Getter, @Builder 等,編譯期生成字節碼,運行時無痕跡。@NonNull 配合 Checker Framework 做靜態分析。特點:寫入 .class 的 RuntimeInvisibleAnnotations 屬性表,JVM 類加載器不加載到內存,但字節碼分析工具 (ASM, Byte Buddy) 和註解處理器 (Annotation Processor) 可讀取。
核心用途:
.class 生成輔助類。特點:寫入 RuntimeVisibleAnnotations,JVM 加載類時解析到內存,Class.getAnnotations() 可獲取。
核心用途:
@Autowired, @Component, @RequestMapping, @Transactional — 容器啟動掃描註解構建 BeanDefinition。@Entity, @Table, @Column — 構建實體元數據模型。@Path, @GET, @RequestBody — 運行時路由分發。@NotNull, @Size (Bean Validation) — 運行時攔截器反射檢查。需要在運行時通過反射讀取?
├─ 是 → RUNTIME
└─ 否
需要在編譯時被註解處理器/字節碼工具讀取?
├─ 是 → CLASS
└─ 否 → SOURCE (純文檀/編譯器提示)
自定義註解可標註多個保留策略 (取最長);但通常明確指定一個。框架設計時:
@MyService)。@GenerateBuilder)。@ThreadSafe)。誤區:
@Retention(RetentionPolicy.CLASS)註解運行時能用反射讀到。
真相:不能。JVM 默認不加載 CLASS 保留註解。若需運行時讀取,必須用 RUNTIME。