Я пытаюсь использовать @Autowired аннотацию со своим универсальным интерфейсом Dao как это:
public interface DaoContainer<E extends DomainObject> {
public int numberOfItems();
// Other methods omitted for brevity
}
Я использую этот интерфейс в своем Контроллере следующим способом:
@Configurable
public class HelloWorld {
@Autowired
private DaoContainer<Notification> notificationContainer;
@Autowired
private DaoContainer<User> userContainer;
// Implementation omitted for brevity
}
Я настроил свой контекст приложения со следующей конфигурацией
<context:spring-configured />
<context:component-scan base-package="com.organization.sample">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<tx:annotation-driven />
Это работает только частично, так как Spring создает и вводит только один экземпляр моего DaoContainer, а именно, DaoContainer. Другими словами, если я спрашиваю userContainer.numberOfItems (); я получаю количество notificationContainer.numberOfItems ()
Я попытался использовать интерфейсы со строгим контролем типов для маркировки корректной реализации как это:
public interface NotificationContainer extends DaoContainer<Notification> { }
public interface UserContainer extends DaoContainer<User> { }
И затем используемый эти интерфейсы как это:
@Configurable
public class HelloWorld {
@Autowired
private NotificationContainer notificationContainer;
@Autowired
private UserContainer userContainer;
// Implementation omitted...
}
Печально это перестало работать к BeanCreationException:
org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.organization.sample.dao.NotificationContainer com.organization.sample.HelloWorld.notificationContainer; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.organization.sample.NotificationContainer] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Теперь, я немного смущен, как я должен продолжить двигаться или использую несколько Дао, даже возможный. Любая справка значительно ценилась бы :)
Можно автоматически подключить столько компонентов, сколько захотите.
Но когда вы используете автоматическое подключение по типу, это может быть только один компонент каждого интерфейса. В вашем сообщении об ошибке говорится, что в контейнере Spring данного интерфейса нет доступного bean-компонента.
Решение:
Ваши недостающие реализации DAO:
@Repository
public class NotificationContainerImpl implements NotificationContainer {}
@Repository
public class UserContainerImpl implements UserContainer {}
Ваш класс обслуживания:
@Service
public class HelloWorld {
@Autowired
private NotificationContainer notificationContainer;
@Autowired
private UserContainer userContainer;
// Implementation omitted...
}
Я заменил аннотацию @Configurable
на @Service
. @Configurable
используется вместе с AspectJ, и это не то, что вам здесь нужно. Вы должны использовать @Component
или его специализацию, например @Service
.
Также не забудьте, что все ваши компоненты Spring должны находиться внутри вашего пакета com.organization.sample
, чтобы контейнер Spring мог их найти.
Надеюсь, это поможет!
Хорошо, я думаю, что нашел довольно разумное решение этой головоломки. Один из способов справиться с этим - создать интерфейс и реализации для каждой сущности в моей модели предметной области (как ранее указал Эспен в своем ответе). Теперь рассмотрим наличие сотен сущностей и, соответственно, сотен реализаций. Это было бы неправильно, не так ли?
Я отказался от строго типизированных субинтерфейсов и вместо этого использую общий интерфейс:
@Service // Using @Service annotation instead @Configurable as Espen pointed out
public class HelloWorld {
@Autowired
private DaoContainer<Notification> notificationContainer;
@Autowired
private DaoContainer<User> userContainer;
// Implementation omitted
}
Реализация моего интерфейса DaoContainer будет выглядеть примерно так:
@Repository
public class DaoContainerImpl<E extends DomainObject> implements DaoContainer<E> {
// This is something I need in my application logic
protected Class<E> type;
public int getNumberOfItems() {
// implementation omitted
}
// getters and setters for fields omitted
}
И, наконец, контекст приложения:
<context:spring-configured />
<context:component-scan base-package="com.organization.sample">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<bean class="com.organization.sample.dao.DaoContainerImpl" id="userContainer">
<property name="type" value="com.organization.sample.domain.DiaryUser" />
</bean>
<bean class="com.organization.sample.dao.DaoContainerImpl" id="notificationContainer">
<property name="type" value="com.organization.sample.domain.DiaryNotification" />
</bean>
По сути, я не мог заставить работать обычную автоматическую проводку, но это решение работает для меня (по крайней мере, на данный момент):)