簡體   English   中英

自動裝配兩個實現相同接口的 bean - 如何將默認 bean 設置為自動裝配?

[英]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 ,即(假設你使用@RepositoryHibernateDeviceDao ):

@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM