Autowiring два beans реализации одного и того же интерфейса - как установить по умолчанию bean для автоустройства?

История:

У меня есть приложение Spring 2.5/Java/Tomcat. Существует следующий bean, который используется во всем приложении во многих местах

public class HibernateDeviceDao implements DeviceDao

и следующий bean, который является новым:

public class JdbcDeviceDao implements DeviceDao

Первый bean настроен так (все beans в пакете включены)

<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: не определено уникальное bean типа [com.sevenp.mobile.samplemgmt.service.dao.DeviceDao]: ожидаемое одиночное соответствие bean, но найдено 2: [deviceDao, jdbcDeviceDao]

из класса, пытающегося autwire bean, как этот

@Autowired
private DeviceDao hibernateDevicDao;

потому что существует два beans, реализующих один и тот же интерфейс.

Вопрос:

Можно ли настроить beans так, чтобы

1. Мне не нужно вносить изменения в существующие классы, у которых уже есть HibernateDeviceDao autowired

2. все еще может использовать второй (новый) bean следующим образом:

@Autowired
@Qualifier("jdbcDeviceDao")

т.е. мне понадобится способ настройки HibernateDeviceDao bean, поскольку по умолчанию bean должен быть автообновлен, одновременно позволяя использовать JdbcDeviceDao, явно указывая это с помощью аннотации @Qualifier.

Что я уже пробовал:

Я попытался установить свойство

autowire-candidate="false"

в конфигурации bean для JdbcDeviceDao:

<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao" autowire-candidate="false">
    <property name="dataSource" ref="jdbcDataSource"/>
</bean>

поскольку документация Spring гласит, что

Указывает, следует ли учитывать этот bean, если  поиск подходящих кандидатов для удовлетворения других bean требования автоувеличивания. Обратите внимание, что это не влияет на явное  ссылки по имени, которые будут решены, даже если указанные  bean не помечен как кандидат на автоспуск. *

который я интерпретировал как означающий, что я мог бы autwire JdbcDeviceDao использовать аннотацию @Qualifier и иметь HibernateDeviceDao по умолчанию bean. По-видимому, моя интерпретация была неправильной, так как это приводит к появлению следующего сообщения об ошибке при запуске сервера:

Неудовлетворительная зависимость типа [класс com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDeviceDao]: ожидается как минимум 1 совпадение bean

входящий в класс, где я пробовал autowiring bean с квалификатором:

@Autowired
@Qualifier("jdbcDeviceDao")

Решение:

skaffman's , чтобы попробовать аннотацию @Resource. Таким образом, у конфигурации есть параметр autowire-кандидат, установленный в false для jdbcDeviceDao, и при использовании jdbcDeviceDao я ссылаюсь на него с помощью аннотации @Resource (вместо @Qualifier):

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

Ответ 1

Я бы предложил маркировать класс DAB Hibernate @Primary, т.е. (если вы использовали @Repository на HibernateDeviceDao):

@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao

Таким образом, он будет выбран в качестве автозапуска автозапуска по умолчанию, без необходимости autowire-candidate на другом bean.

Кроме того, вместо использования @Autowired @Qualifier я считаю более элегантным использовать @Resource для выбора конкретного beans, т.е.

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

Ответ 2

Как насчет @Primary?

Указывает, что a bean следует присваивать предпочтение, когда несколько кандидатов имеют квалификацию для автосогласования однозначной зависимости. Если между кандидатами существует ровно один "первичный" bean, это будет значение с автопрограммой. Эта аннотация семантически эквивалентна атрибуту <bean> element primary в Spring XML.

@Primary
public class HibernateDeviceDao implements DeviceDao

Или если вы хотите, чтобы ваша версия Jdbc использовалась по умолчанию:

<bean id="jdbcDeviceDao" primary="true" class="com.initech.service.dao.jdbc.JdbcDeviceDao">

@Primary также отлично подходит для тестирования интеграции, когда вы можете легко заменить производство bean на заглушенную версию, аннотируя его.

Ответ 3

Для Spring 2.5 нет @Primary. Единственный способ - использовать @Qualifier.