Задний план:
У меня есть приложение Spring 2.5 / Java / Tomcat. Существует следующий компонент, который используется во всем приложении во многих местах.
public class HibernateDeviceDao implements DeviceDao
и следующий боб, который является новым:
public class JdbcDeviceDao implements DeviceDao
Первый компонент настроен так (все компоненты пакета включены)
<context:component-scan base-package="com.initech.service.dao.hibernate" />
Второй (новый) компонент настраивается отдельно
<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]: ожидается один соответствующий бин, но найдено 2: [deviceDao, jdbcDeviceDao]
из класса, пытающегося автоматически подключить боб, как это
@Autowired
private DeviceDao hibernateDevicDao;
потому что есть два компонента, реализующие один и тот же интерфейс.
Вопрос:
Можно ли настроить бины так, чтобы
1. Мне не нужно вносить изменения в существующие классы, которые уже имеют HibernateDeviceDao
автопроводку
2. все еще в состоянии использовать второй (новый) компонент следующим образом:
@Autowired
@Qualifier("jdbcDeviceDao")
Т.е. мне понадобится способ настроить HibernateDeviceDao
bean-компонент в качестве bean-компонента по умолчанию для автоматической проводки, позволяя одновременно использовать a JdbcDeviceDao
при явном указании этого с @Qualifier
аннотацией.
Что я уже пробовал:
Я пытался установить свойство
autowire-candidate="false"
в конфигурации компонента для JdbcDeviceDao:
<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao" autowire-candidate="false">
<property name="dataSource" ref="jdbcDataSource"/>
</bean>
потому что в документации Spring сказано, что
Указывает, следует ли учитывать этот компонент при поиске подходящих кандидатов для соответствия требованиям к автоматическому подключению другого компонента. Обратите внимание, что это не влияет на явные ссылки по имени, которые будут разрешены, даже если указанный bean-компонент не помечен как кандидат для автоматической передачи. *
что я интерпретировал, чтобы означать, что я все еще могу автоматически подключаться JdbcDeviceDao
с использованием @Qualifier
аннотации и иметь HibernateDeviceDao
компонент по умолчанию. Очевидно, что моя интерпретация была неверной, так как это приводит к следующему сообщению об ошибке при запуске сервера:
Неудовлетворенная зависимость типа [class com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDeviceDao]: ожидается как минимум 1 соответствующий компонент
пришедший из класса, где я пытался автоматически связать бин с классификатором:
@Autowired
@Qualifier("jdbcDeviceDao")
Решение:
skaffman в предложение попробовать @Resource аннотацию работал. Таким образом, для конфигурации autowire-кандидата установлено значение false для jdbcDeviceDao, и при использовании jdbcDeviceDao я обращаюсь к нему с помощью аннотации @Resource (вместо @Qualifier):
@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;
источник
Ответы:
Я хотел бы предложить маркировку класса Hibernate DAO с
@Primary
, то есть (если вы использовали@Repository
наHibernateDeviceDao
):Таким образом, он будет выбран как кандидат по умолчанию для автоматической передачи, без необходимости
autowire-candidate
использования другого компонента.Кроме того, вместо того, чтобы использовать
@Autowired @Qualifier
, я считаю более элегантным использовать@Resource
для выбора конкретных бобов, то естьисточник
@Resource
аннотацию, как я также предложил.@Resource
и@Qualifier
, кроме того факта, что первый относительно новее, чем второй?Как насчет
@Primary
?Или, если вы хотите, чтобы ваша версия Jdbc использовалась по умолчанию:
@Primary
также отлично подходит для интеграционного тестирования, когда вы можете легко заменить рабочий компонент на заглушенную версию, пометив ее аннотацией.источник
primary=""
атрибут был доступен ранее. Просто объявитеHibernateDeviceDao
в XML и исключите его из сканирования компонентов / аннотаций.Для весны 2.5 нет
@Primary
. Единственный способ - это использовать@Qualifier
.источник
источник
Причина, по которой @Resource (name = "{имя вашего дочернего класса}") работает, но @Autowired иногда не работает, заключается в разнице их последовательности соответствия
Соответствующая последовательность @Autowire
Type, Qualifier, Name
Соответствующая последовательность @Resource
Name, Type, Qualifier
Более подробное объяснение можно найти здесь:
Inject and Resource и Autowired аннотации
В этом случае другой дочерний класс, унаследованный от родительского класса или интерфейса, сбивает с толку @Autowire, поскольку они принадлежат к одному типу; Поскольку @Resource использует Name в качестве первого соответствующего приоритета, это работает.
источник