Spring 3 DI с использованием универсального интерфейса DAO - PullRequest
7 голосов
/ 17 мая 2010

Я пытаюсь использовать аннотацию @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 (); Я получаю номер уведомленияContainer.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)}

Теперь, я немного запутался, как мне действовать, или даже возможно использование нескольких Дао. Любая помощь будет принята с благодарностью:)

Ответы [ 2 ]

2 голосов
/ 19 мая 2010

Хорошо, я думаю, что нашел довольно разумное решение для этой головоломки. Один из способов справиться с этим - создать интерфейс и реализации для каждой сущности в моей модели предметной области (как Эспен указал в своем ответе ранее). Теперь рассмотрим наличие сотен сущностей и, соответственно, сотен реализаций. Это было бы неправильно, не так ли?

Я отказался от строго типизированных подчиненных интерфейсов и вместо этого использую общий интерфейс:

@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>

Так что в принципе я не мог заставить работать чистую универсальную автопроводку, но это решение работает для меня (по крайней мере, пока):)

0 голосов
/ 17 мая 2010

Можно автоматически соединять столько бобов, сколько вам нужно.

Но когда вы используете автопровод по типу, это может быть только один из bean-компонентов каждого интерфейса. В вашем сообщении об ошибке говорится, что в контейнере 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 мог их найти.

Надеюсь, это поможет!

...