【发布时间】:2012-05-19 00:41:18
【问题描述】:
背景:
我有一个 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")
即我需要一种将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's suggestion 尝试使用@Resource 注释。因此配置将 jdbcDeviceDao 的 autowire-candidate 设置为 false 并且在使用 jdbcDeviceDao 时我使用 @Resource 注释(而不是 @Qualifier)来引用它:
@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;
【问题讨论】:
-
如果我在代码中的 100 个地方使用这个接口,并且我想全部切换到另一个实现,我不想在所有地方都更改限定符或资源注释。而且我也不想更改任一实现的代码。为什么没有像 Guice 那样的显式绑定可能性?
标签: java spring spring-mvc autowired