自 Spring 2.5 引入註解配置以來,這場爭論從未停止。本文從原理、優缺點、適用場景、混合策略四個維度,為你提供架構級選型依據。
| 維度 | 註解配置 (@Component, @Autowired...) | XML 配置 (<bean>, <property>) |
|---|---|---|
| 元數據位置 | 分散在 Java 類別內部 | 集中在獨立 XML 文件 |
| 綁定時機 | 編譯期 (源碼級) | 運行期 (部署期可修改) |
| 類型安全 | 編譯器檢查,重構友好 | 字符串引用,重構易出錯 |
| 第三方類支援 | ❌ 無法標註非源碼類 | ✅ 完美支援 |
| 配置複雜度 | 適合簡單、固定依賴 | 適合複雜、動態、條件化裝配 |
| 可讀性/內聚性 | 代碼配置一體,內聚性高 | 分離關注點,但需來回切換文件 |
// 註解配置:零配置映射,反射自動推斷
@Entity
@Table(name = "users")
public class User {
@Id @GeneratedValue
private Long id;
@Column(name = "user_name", length = 50)
private String username; // 欄位名、類型自動映射
@OneToMany(mappedBy = "user")
private List orders; // 關係映射
}
// XML 等效配置:需手動維護每個屬性映射
//
//
//
//
//
//
//
當實體屬性與資料庫欄位命名一致、類型對應標準時,註解配置**零冗余**,重構時重命名欄位僅需改一處。
<bean profile="prod">、<property value="#{systemProperties['key']}" SpEL 動態注入<aop:config>、<tx:advice> 比 @Transactional 更靈活 (方法級切點、異常回滾規則)
// 1. 業務層:註解掃描 + 註解注入 (高內聚、穩定依賴)
@Service
public class OrderService {
@Autowired private OrderRepository orderRepo; // 介面注入
@Autowired private PaymentClient paymentClient; // 第三方客戶端 (需 XML 裝配)
@Transactional(rollbackFor = Exception.class)
public void createOrder(OrderDTO dto) { ... }
}
// 2. 基礎設施層:XML 集中配置 (環境敏感、第三方類)
| 場景 | 首選 | 理由 |
|---|---|---|
| 自研 Service/Repository/Controller | 註解 (@Service, @Autowired) | 內聚性高、依賴固定、重構安全 |
| 第三方 DataSource/Client/Template | XML <bean> | 無源碼、參數環境相關、需銷毀回調 |
| 事務/快取/AOP 切面規則 | XML (tx:aop, cache:advice) | 集中管理、方法模式匹配、非侵入式 |
| 多環境差異化參數 | XML + PropertyPlaceholder | 部署期修改、無需重編譯 |
| 條件化 Bean 裝配 (@Conditional) | 註解 (@ConditionalOnProperty) | 類級條件、編譯期類型安全 |
@ImportResource("classpath:infrastructure.xml") 在主配置類引入 XML配置方式沒有絕對優劣,只有「是否匹配變化維度」。讓穩定的內聚在代碼,讓易變的外置在配置,這才是架構師的智慧。