【问题标题】:Spring IoC and Generic Interface Type [duplicate]Spring IoC 和通用接口类型
【发布时间】:2009-02-02 12:10:57
【问题描述】:

我正在尝试将 Spring IoC 与这样的接口一起使用:

public interface ISimpleService<T> {
    void someOp(T t);
    T otherOp();
}

Spring 能否提供基于泛型类型参数 T 的 IoC?我的意思是,像这样:

public class SpringIocTest {
    @Autowired
    ISimpleService<Long> longSvc;

    @Autowired
    ISimpleService<String> strSvc;
    //...
}

当然,我上面的例子是行不通的:

expected single matching bean but found 2: [serviceLong, serviceString]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessAfterInstantiation(AutowiredAnnotationBeanPostProcessor.java:243)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:957)

我的问题:是否可以在对接口或实现类进行最少修改的情况下提供类似的功能?例如,我知道我可以使用@Qualifiers,但我想让事情尽可能简单。

【问题讨论】:

标签: java spring inversion-of-control types generics


【解决方案1】:

我不相信这是可能的,因为擦除。在进行全自动装配时,我们通常会切换到强类型子接口:

public interface LongService extends ISimpleService<Long> {}
public interface StringService extends ISimpleService<String> {}

在进行此切换时,我们发现我们实际上非常喜欢它,因为它使我们能够更好地进行“查找使用”跟踪,这是泛型接口所松散的。

【讨论】:

  • 你如何处理代码重复?可能有一个也是通用的中产阶级,不是吗? Tks
  • 唯一需要复制的是标记界面。但是你没有显示你的实现类,所以我不知道你是否在做我没有看到的任何事情!
  • 实施将适合另一个 SO 问题:)
【解决方案2】:

我认为没有资格赛是不可能的

我会尝试用 genericDAO 展示我的解决方案,如果有点详细,抱歉

接口和实现类定义

public interface GenericDAO<T, ID extends Serializable> (...)

public class GenericDAOImpl<T, ID extends Serializable>
    implements GenericDAO<T, ID> 
    (...) important is this constructor
    public GenericDAOImpl(Class<T> persistentClass) {
       this.persistentClass = persistentClass;
    }

spring bean 定义,注意 abstract="true"

<bean id="genericHibernateDAO" class="de.optimum24.av.pers.ext.hibernate.dao.GenericDAOImpl"
      abstract="true">
    <description>
        <![CDATA[
            Definition des GenericDAO.
        ]]>
    </description>
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

使用此 genericDAO 无需特殊实现类

 <bean id="testHibernateChildDao" class="de.optimum24.av.pers.ext.hibernate.dao.GenericDAOImpl">
    <property name="sessionFactory" ref="sessionFactory" />
    <constructor-arg>
        <value>de.optimum24.av.pers.test.hibernate.domain.TOChild</value>
    </constructor-arg>
</bean>

注意带有具体类的constructor-arg,如果您使用Spring Annotation,您需要这样做:

@Autowired
@Qualifier(value = "testHibernateChildDao")
private GenericDAO<TOChild, Integer> ToChildDAO;

区分genericDao Beans的各种版本(注意限定符直接引用Beanname)

将此 genericDAO 与特殊实现类一起使用

接口和类

public interface TestHibernateParentDAO extends GenericDAO<TOParent, Integer>{
  void foo();
}
public class TestHibernateParentDAOImpl extends GenericDAOImpl<TOParent, Integer>
                              implements TestHibernateParentDAO {
  @Override
  public void foo() {
      //* no-op */
  }
}

Bean 定义,注意上面抽象 genericDAO 的“父”引用

<bean id="testHibernateParentDao" class="de.optimum24.av.pers.test.hibernate.dao.TestHibernateParentDAOImpl"
      parent="genericHibernateDAO" />

和 Spring Annotation 的用法

@Autowired
private TestHibernateParentDAO ToParentDAO;

【讨论】:

  • 关于注解和 XML 用法的好答案。从长远来看,这个解决方案对您有用吗?使用这种方法有哪些缺点,比如能够更轻松地跟踪代码(Krosenvold 在第 1 篇文章中提到)?
  • 这更像是一个组织/知识问题,如果开发人员知道它确实工作的过程,那么这种通用方法肯定比使用(标记)接口更难处理
【解决方案3】:

如果泛型类型在编译时完全具体化,则可以通过擦除来做到这一点。在这种情况下,类型信息可通过以下任一方式获得:

Class#getGenericInterfaces()
Class#getGenericSuperclass()

这是 Guice 的主要特性,Spring 中缺少的。

【讨论】:

    【解决方案4】:

    不要让你的界面通用。改用你的方法:

    public interface ISimpleService {
        public <T> T doSomething(T param);
    }
    

    希望对你有帮助。

    【讨论】:

      【解决方案5】:

      当使用某些持久层执行此操作时,Spring Data 会为您执行此操作。如果您使用 JPA、Neo4j、MongoDB 或其他它支持的东西,Spring Data 是一个非常棒的节省时间和简化工具。

      【讨论】:

        【解决方案6】:

        另一种选择是在一侧使用名称注释实现 bean 的接口,并在另一侧使用指向创建名称的限定符进行注释:) 这是我在项目中使用的一个快速示例:

         public interface IDAO<T> {
        
                 public void insert(T model);
                 public void update(T model);
                 public void delete(T model);
          }
        

        作为前身的抽象类:

        public abstract class AbstractHibernateDAO {
        
                 protected SessionFactory sessionFactory;
        
                 protected Session currentSession() {
                     return sessionFactory.getCurrentSession();
                 }
            }
        

        实体用户抽象类的实现:

        @Repository(value = "userRepository") 
        public class UserDAO extends AbstractHibernateDAO implements IDAO<User> {
        
            @Autowired
            public UserDAO(SessionFactory sessionFactory) {
                this.sessionFactory = sessionFactory;
            }
        
            @Override
            public void insert(User user) {
                currentSession().save(user);
            }
        
            @Override
            public void update(User user) {
                currentSession().update(user);
            }
        
            @Override
            public void delete(User user) {
                currentSession().delete(user);
            } 
        

        }

        最后注入正确的实现:

        @Resource
        @Qualifier(value = "userRepository")
        IDAO<User> userPersistence;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-03
          • 1970-01-01
          • 1970-01-01
          • 2013-10-25
          • 1970-01-01
          相关资源
          最近更新 更多