自动连接实现相同接口的两个 bean ——如何将默认 bean 设置为自动连接?

背景:

我有一个 Spring 2.5/Java/Tomcat 应用程序

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.NoSuchBeanDefinition itionException: 没有类型为[ com.sevenp.mobile.samplemgmt.service.Dao 的唯一 bean。DeviceDao ]被定义为: 预期的单个匹配 bean,但找到了2: [ deviceDao,jdbcDeviceDao ]

来自一个试图像这样自动装配豆子的类

@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 没有标记为 autowire 候选项

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

类型[ com.sevenp.mobile.samplemgmt.service.dao.jdbc. JdbcDeviceDao ]的不满意依赖项: 预计至少有1个匹配的 bean

来自我曾经尝试使用限定符自动装配 bean 的类:

@Autowired
@Qualifier("jdbcDeviceDao")

解决方案:

Skaffman 的 建议尝试@Resource 注释是可行的。因此,对于 jdbcDeviceDao,配置的 autowire 候选设置为 false,当使用 jdbcDeviceDao 时,我使用@Resource 注释(而不是@Qualifier)引用它:

@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;
159230 次浏览

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

@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao

这样,它将被选择为默认的自动连接候选项,而不需要在另一个 bean 上使用 autowire-candidate

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

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

@Primary呢?

指示 bean 应该给 当多个候选人有资格自动装配时,优先考虑一个单值依赖项。如果候选者中只存在一个“主”bean,那么它将是自动连接的值。这个注释在语义上等同于 SpringXML 中 <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 作为第一匹配优先级,那么它就可以工作。