專案啟動或注入時拋出:
expected single matching bean but found 2: defaultSettingDAO, serializeSettingDAO
程式碼片段:
@Service
@Transactional(rollbackFor = Exception.class)
public class DefaultSerializeSettingManage implements SerializeSettingService {
@Autowired
SerializeSettingDAO settingdao; // 變數名為 settingdao
}
明明每個介面只有一個實現類,為何 Spring 認定找到兩個 Bean?
Spring 在掃描 @Component、@Service、@Repository 等註解類時,若未指定 value,會以類名首字母小寫作為 Bean 名稱:
DefaultSettingDAO → bean name: defaultSettingDAOSerializeSettingDAO → bean name: serializeSettingDAO當注入點型別為介面 SerializeSettingDAO 時,Spring 容器中有兩個型別相容的 Bean(DefaultSettingDAO 實現了同一介面,或被誤掃描),導致 byType 自動裝配發現多個候選者,拋出 NoUniqueBeanDefinitionException。
@Autowired
@Qualifier("serializeSettingDAO")
private SerializeSettingDAO settingdao;
明確告訴 Spring 使用哪個 Bean,語義清晰,不依賴變數命名。
在其中一個實現類上加 @Primary:
@Repository
@Primary
public class SerializeSettingDAOImpl implements SerializeSettingDAO { ... }
當多個候選者存在時,Spring 會優先注入標記 @Primary 的 Bean。
@Autowired private SerializeSettingDAO serializeSettingDAO; // 變數名 = bean name
Spring 先嘗試 byType,失敗後回退 byName;若變數名恰好等同於目標 Bean 名稱,即可成功注入。但此方式耦合變數命名,重構風險較大,不建議作為首選。
原變數 settingdao 不匹配任何 Bean 名稱,Spring 僅能 byType,發現兩個候選 → 報錯。
改為 serializeSettingDAO 後,byName 精確命中唯一 Bean,繞過 byType 衝突。
XxxDAO / XxxDAOImpl),減少同類型 Bean 共存機率。理解 Spring 的「byType → byName → @Qualifier」解析順序,能快速定位並徹底解決此類裝配衝突。