【问题标题】:Spring 3 DI using generic DAO interfaceSpring 3 DI 使用通用 DAO 接口
【发布时间】:2011-02-20 06:53:06
【问题描述】:

我正在尝试将 @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)}

现在,我有点困惑我应该如何进行,或者甚至可能使用多个 Dao。任何帮助将不胜感激:)

【问题讨论】:

  • 我没有看到您的接口的任何实现类。有多少个,它们长什么样?
  • 我没有明确的接口实现,因为我希望我可以使用通用 dao 类(即 DaoContainer)。我可以创建明确的实现(正如 Espen 在他的回答中指出的那样)。这感觉不合理,因为我试图尽可能多地利用 Java 泛型。但是,我确实有 DaoContainerImpl.
  • 也许stackoverflow.com/questions/502994/… 是一个解决方案

标签: spring interface dependency-injection annotations autowired


【解决方案1】:

可以自动装配任意数量的 bean。

但是当您使用按类型自动装配时,它只能是每个接口的 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...
}

我用@Service 替换了@Configurable 注释。 @Configurable 与 AspectJ 一起使用,这不是您想要的。您必须使用@Component 或它的专门化形式,例如@Service

还要记住将所有 Spring 组件放在 com.organization.sample 包中,以使 Spring 容器能够找到它们。

我希望这会有所帮助!

【讨论】:

    【解决方案2】:

    好的,我想我已经为这个谜题找到了一个相当合理的解决方案。解决这个问题的一种方法是为我的域模型中的每个实体创建接口和实现(正如 Espen 在他之前的回答中指出的那样)。现在,考虑拥有数百个实体和数百个实现。那感觉不对吧?

    我已经放弃了强类型子接口,而是使用通用接口:

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

    所以基本上我无法让纯通用自动装配工作,但这个解决方案对我有用(至少现在):)

    【讨论】:

    • 我知道这是一个老问题,但您的解决方案与stackoverflow.com/questions/502994/… 中描述的使用标记接口非常相似。我想污染 Spring 配置文件或 java 源代码树取决于个人喜好。
    猜你喜欢
    • 2014-12-04
    • 1970-01-01
    • 2018-01-10
    • 2013-06-07
    • 2018-01-25
    • 2022-08-16
    • 2021-08-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多