146

背景:

我有一个 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>

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

嵌套异常是 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")

即,我需要一种方法将HibernateDeviceDaobean 配置为要自动装配的默认 bean,同时允许在使用注释JdbcDeviceDao明确指定时使用 the 。@Qualifier

我已经尝试过的:

我尝试设置属性

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 未标记为自动装配候选者,也会得到解决。*

我将其解释为我仍然可以JdbcDeviceDao使用@Qualifier注释自动装配并将其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;
4

5 回答 5

135

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

@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao

这样,它将被选为默认的自动装配候选者,而无需autowire-candidate在其他 bean 上。

另外,比起使用,我发现用于挑选特定的豆子@Autowired @Qualifier更优雅,即@Resource

@Resource(name="jdbcDeviceDao")
DeviceDao deviceDao;
于 2012-05-10T12:35:52.893 回答
39

怎么样@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 替换为存根版本时,它也非常适合集成测试。

于 2012-05-10T12:37:01.490 回答
9

对于 Spring 2.5,没有@Primary. 唯一的方法是使用@Qualifier.

于 2012-05-10T12:46:50.970 回答
3
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.
于 2019-03-07T17:08:42.853 回答
1

@Resource(name = "{your child class name}") 有效但@Autowired 有时不起作用的原因是因为它们的匹配顺序不同


@Autowire类型、限定符、名称的匹配顺序


@Resource Name, Type, Qualifier的匹配顺序

更详细的解释可以在这里找到:
Inject and Resource and Autowired annotations

在这种情况下,从父类或接口继承的不同子类会混淆@Autowire,因为它们来自同一类型;由于 @Resource 使用 Name 作为第一个匹配优先级,它可以工作。

于 2020-02-03T03:17:07.147 回答