當我們在方法上標註 @Override 時,編譯器會檢查是否真正覆蓋了父類方法;運行期 JVM 則不保留該註解。這背後是 註解保留策略 與 處理器機制 協作的結果。本文系統講解註解生命週期、元註解、自定義註解定義、反射讀取,並延伸至 Servlet 3.0、Spring/Hibernate、ADF 框架中的實戰應用。
JDK 5.0 在 java.lang.annotation 提供四大元註解,專門「註解其他註解」:
| 元註解 | 作用 | 關鍵屬性/值 |
|---|---|---|
@Documented |
標記是否納入 Javadoc | 無屬性,標記型 |
@Retention |
聲明生命週期 | SOURCE(編譯期丟棄)、CLASS(類加載丟棄,默認)、RUNTIME(運行期保留,可反射讀取) |
@Target |
限制註解使用位置 | ElementType.TYPE/FIELD/METHOD/PARAMETER/CONSTRUCTOR/LOCAL_VARIABLE/ANNOTATION_TYPE/PACKAGE |
@Inherited |
允許子類繼承父類註解 | 僅對 TYPE 生效 |
SOURCE:@Override、@SuppressWarnings — 僅供編譯器檢查。CLASS:字節碼分析工具(如 Lombok 編譯期處理)。RUNTIME:自定義註解首選,配合反射實現框架級功能(路由映射、事務控制、驗證等)。@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Todo {
enum Priority { LOW, MEDIUM, HIGH }
enum Status { STARTED, NOT_STARTED }
String author() default "Yash";
Priority priority() default Priority.LOW;
Status status() default Status.NOT_STARTED;
}
規則:
String、Class、枚舉、註解類型、及其數組。default 指定預設值。value(),使用時可省略屬性名:@Author("Yash")。Class<?> clazz = BusinessLogic.class;
for (Method m : clazz.getMethods()) {
Todo todo = m.getAnnotation(Todo.class);
if (todo != null) {
System.out.println("Method: " + m.getName());
System.out.println("Author: " + todo.author());
System.out.println("Priority: " + todo.priority());
}
}
核心 API:getAnnotation(Class<T>)、getAnnotations()、isAnnotationPresent()。
| 註解 | 用途 |
|---|---|
@WebServlet | 聲明 Servlet 配置(替代 web.xml) |
@WebFilter | 聲明 Filter |
@WebListener | 聲明 Listener |
@ServletSecurity | HTTP 安全約束 |
@MultipartConfig | 文件上傳配置 |
@Component、@Autowired、@Transactional、@RequestMapping 等,結合 AOP 在切面織入邏輯。@Entity、@Table、@Id、@Column、@OneToMany 等,替代 XML 映射。註解優於標記接口:可針對單個方法/字段定義元數據,粒度更細。
ADF 不採用 AOP,註解無法直接通過切面攔截。若需註解驅動功能,須採用繼承/模板方法或手動掃描反射在基類中統一處理。
@Target 精確限定使用位置,防止濫用。AnnotationProcessor(編譯期)或反射(運行期)實現具體邏輯,註解本身「不執行代碼」。掌握註解機制,是從「使用框架」進階到「構建框架」的關鍵一步。