![](/img/trans.png)
[英]Injecting spring bean among two beans- implementing same interface
[英]Autowiring two beans implementing same interface - how to set default bean to autowire?
我有一個 Spring 2.5/Java/Tomcat 應用程序。 有下面這個bean,在整個應用程序中很多地方都會用到
public class HibernateDeviceDao implements DeviceDao
以及以下新豆:
public class JdbcDeviceDao implements DeviceDao
第一個bean是這樣配置的(包中的所有bean都包含在內)
<context:component-scan base-package="com.initech.service.dao.hibernate" />
第二個(新)bean 單獨配置
<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
<property name="dataSource" ref="jdbcDataSource">
</bean>
這會導致(當然)在啟動服務器時出現異常:
嵌套異常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: 沒有定義類型 [com.sevenp.mobile.samplemgmt.service.dao.DeviceDao] 的唯一 bean:預期的單個匹配 bean,但發現 2: [deviceDao, jdbcDeviceDao]
來自一個試圖像這樣自動裝配 bean 的類
@Autowired
private DeviceDao hibernateDevicDao;
因為有兩個 bean 實現了相同的接口。
是否可以配置bean,以便
1.我不必對已經自動裝配HibernateDeviceDao
現有類進行更改
2.仍然可以像這樣使用第二個(新的)bean:
@Autowired
@Qualifier("jdbcDeviceDao")
即我需要一種方法來將HibernateDeviceDao
bean 配置為要自動裝配的默認 bean,同時允許在使用@Qualifier
注釋顯式指定時使用JdbcDeviceDao
。
我嘗試設置屬性
autowire-candidate="false"
在 JdbcDeviceDao 的 bean 配置中:
<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao" autowire-candidate="false">
<property name="dataSource" ref="jdbcDataSource"/>
</bean>
因為 Spring 文檔說
指示在尋找匹配候選以滿足另一個 bean 的自動裝配要求時是否應考慮此 bean。 請注意,這不會影響按名稱的顯式引用,即使指定的 bean 未標記為自動裝配候選者,也會得到解析。*
我認為這意味着我仍然可以使用@Qualifier
注釋自動裝配JdbcDeviceDao
,並將HibernateDeviceDao
作為默認 bean。 不過,顯然我的解釋不正確,因為這會在啟動服務器時導致以下錯誤消息:
[class com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDeviceDao] 類型的不滿意依賴:預計至少有 1 個匹配的 bean
來自我嘗試使用限定符自動裝配 bean 的類:
@Autowired
@Qualifier("jdbcDeviceDao")
skaffman 建議嘗試使用 @Resource 注釋。 因此,配置將 jdbcDeviceDao 的 autowire-candidate 設置為 false,並且在使用 jdbcDeviceDao 時,我使用 @Resource 注釋(而不是 @Qualifier)來引用它:
@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;
我建議標記使用Hibernate的DAO類@Primary
,即(假設你使用@Repository
對HibernateDeviceDao
):
@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao
這樣它將被選為默認的自動裝配候選者,而無需在另一個 bean 上autowire-candidate
。
另外,我發現使用@Resource
來挑選特定的 bean 比使用@Autowired @Qualifier
更優雅,即
@Resource(name="jdbcDeviceDao")
DeviceDao deviceDao;
@Primary
怎么樣?
指示當多個候選者有資格自動裝配單值依賴項時,應該優先考慮一個 bean。 如果候選中恰好存在一個“主要”bean,它將是自動裝配的值。 這個注解在語義上等同於 Spring XML 中
<bean>
元素的primary
屬性。
@Primary
public class HibernateDeviceDao implements DeviceDao
或者,如果您希望默認使用 Jdbc 版本:
<bean id="jdbcDeviceDao" primary="true" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
@Primary
也非常適合集成測試,因為您可以通過注釋輕松地將生產 bean 替換為存根版本。
對於 Spring 2.5,沒有@Primary
。 唯一的方法是使用@Qualifier
。
The use of @Qualifier will solve the issue.
Explained as below example :
public interface PersonType {} // MasterInterface
@Component(value="1.2")
public class Person implements PersonType { //Bean implementing the interface
@Qualifier("1.2")
public void setPerson(PersonType person) {
this.person = person;
}
}
@Component(value="1.5")
public class NewPerson implements PersonType {
@Qualifier("1.5")
public void setNewPerson(PersonType newPerson) {
this.newPerson = newPerson;
}
}
Now get the application context object in any component class :
Object obj= BeanFactoryAnnotationUtils.qualifiedBeanOfType((ctx).getAutowireCapableBeanFactory(), PersonType.class, type);//type is the qualifier id
you can the object of class of which qualifier id is passed.
@Resource(name = "{your child class name}") 工作但@Autowired 有時不工作的原因是因為它們的匹配順序不同
@Autowire 的匹配順序
類型、限定符、名稱
@Resource 的匹配順序
名稱、類型、限定符
更詳細的解釋可以在這里找到:
注入和資源以及自動裝配的注釋
在這種情況下,從父類或接口繼承的不同子類會混淆@Autowire,因為它們來自同一類型; 由於@Resource 使用 Name 作為第一個匹配的優先級,它可以工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.