java - Autowiring 两个实现相同接口(interface)的 bean - 如何将默认 bean 设置为 Autowiring ?

标签 java spring spring-mvc autowired

背景:

我有一个 Spring 2.5/Java/Tomcat 应用程序。有下面这个bean,在整个应用中很多地方都用到了

public class HibernateDeviceDao implements DeviceDao

以及以下新的bean:

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>

这会导致(当然)在启动服务器时出现异常:

nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.sevenp.mobile.samplemgmt.service.dao.DeviceDao] is defined: expected single matching bean but found 2: [deviceDao, jdbcDeviceDao]

来自一个试图像这样 Autowiring bean 的类

@Autowired
private DeviceDao hibernateDevicDao;

因为有两个 bean 实现了相同的接口(interface)。

问题:

是否可以配置 bean 以便

1.我不必更改现有的类,它们已经 Autowiring 了 HibernateDeviceDao

2. 仍然可以像这样使用第二个(新)bean:

@Autowired
@Qualifier("jdbcDeviceDao")

即我需要一种方法来将 HibernateDeviceDao bean 配置为要 Autowiring 的默认 bean,同时允许在使用 @ 明确指定时使用 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 文档是这么说的

Indicates whether or not this bean should be considered when looking for matching candidates to satisfy another bean's autowiring requirements. Note that this does not affect explicit references by name, which will get resolved even if the specified bean is not marked as an autowire candidate.*

我解释为我仍然可以使用 @Qualifier 注释 Autowiring JdbcDeviceDao 并将 HibernateDeviceDao 作为默认 bean。不过,显然我的解释是不正确的,因为这会在启动服务器时导致以下错误消息:

Unsatisfied dependency of type [class com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDeviceDao]: expected at least 1 matching bean

来 self 尝试使用限定符 Autowiring bean 的类:

@Autowired
@Qualifier("jdbcDeviceDao")

解决方案:

skaffman's suggestion尝试 @Resource 注释工作。因此配置将 jdbcDeviceDao 的 autowire-candidate 设置为 false 并且在使用 jdbcDeviceDao 时我使用 @Resource 注释(而不是 @Qualifier)来引用它:

@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;

最佳答案

我建议用 @Primary 标记 Hibernate DAO 类,即(假设您在 HibernateDeviceDao 上使用了 @Repository):

@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao

这样它将被选为默认的 Autowiring 候选者,而无需在另一个bean上autowire-candidate

另外,我发现使用 @Resource 来挑选特定的 bean 比使用 @Autowired @Qualifier 更优雅,即

@Resource(name="jdbcDeviceDao")
DeviceDao deviceDao;

关于java - Autowiring 两个实现相同接口(interface)的 bean - 如何将默认 bean 设置为 Autowiring ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10534053/

相关文章:

java - 当我使用 @Query 时,为方法使用命名参数

java - Spring Data Rest not working——寻找无限递归错误的根源

spring - hibernate : Single out a column containing binary data which shouldn't be loaded

java - 是否为每次迭代创建了 for 循环内的引用变量声明?

java - 硬编码密码的替代方案

Spring 安全: Controller method access to certain roles

java - 是否有一种标准方法来验证数组中多个项目之间的约束?

java - Spring MVC Controller 配置 - 混合注释和 XML @PathVariable

java - Eclipse 错误 com.google.android.gms.ads 无法解析

java - WebFlux DataBufferLimitException : Part headers exceeded the memory usage limit of 8192 bytes