Java Spring IoC 和通用接口类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/502994/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:28:41  来源:igfitidea点击:

Spring IoC and Generic Interface Type

javaspringinversion-of-controltypesgenerics

提问by Miguel Ping

I'm trying to use Spring IoC with an interface like this:

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

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

Can Spring provide IoC based on the generic type argument T? I mean, something like this:

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

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

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

Of course, my example above does not work:

当然,我上面的例子不起作用:

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)

My Question: is it possible to provide a similar functionality with minimum modifications to either the Interface or the implementing classes? I know for instance I can use @Qualifiers, but I want to keep things as simple as possible.

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

采纳答案by krosenvold

I do not believe this is possible due to erasure. We generally switched to strongly typed sub-interfaces when going for full-autowiring:

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

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

Upon doing this switch we found we actually liked this pretty well, because it allows us to do "find usage" tracking much better, something you loose with the generics interfaces.

在进行此切换时,我们发现我们实际上非常喜欢它,因为它使我们能够更好地进行“查找使用”跟踪,而您在泛型接口中会丢失一些东西。

回答by Michael Pralow

i don't think thats possible without Qualifier

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

ill try to show my Solutions with a genericDAO, sorry if it's a bit detailed

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

the Interface and Implementation Class Definition

接口和实现类定义

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;
    }

the spring bean definition, notice the abstract="true"

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>

Using this genericDAO without special implementation Class

使用这个没有特殊实现类的 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>

notice the constructor-arg with an concrete Class, if you work with Spring Annotation you need to do:

注意带有具体类的构造函数参数,如果您使用 Spring Annotation,则需要执行以下操作:

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

to distinguish the various versions of genericDao Beans (notice the Qualifier with direct Reference to the Beanname)

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

Using this genericDAO with special implementation Class

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

the Interface and Class

接口和类

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

the Bean Definition, notice the "parent" Reference to the abstract genericDAO above

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

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

and usage with Spring Annotation

和 Spring Annotation 的使用

@Autowired
private TestHibernateParentDAO ToParentDAO;

回答by Razvan

Don't make your interface generic. Make your methods, instead:

不要让你的界面通用。制作你的方法,而不是:

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

Hope it helps.

希望能帮助到你。

回答by JasonQR

It is possible to do this with erasure, if the generic type is fully reified at compile-time. In this case the type information is available via either of:

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

Class#getGenericInterfaces()
Class#getGenericSuperclass()

This is the major feature of Guice which is missing from Spring.

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

回答by CorayThan

When doing this with certain persistence layers, Spring Datadoes this for you. Spring Data is a really great time-saving and simplification tool if you are using JPA, or Neo4j, or MongoDB, or something else that it supports.

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

回答by s0vet

Another option is to annotate the interface implementing bean with name on one side and to annotate with qualifier pointing to created name on the other side :) Here is a quick example I am using in my project :

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

 public interface IDAO<T> {

         public void insert(T model);
         public void update(T model);
         public void delete(T model);
  }

Abstract class as predecessor :

抽象类作为前身:

public abstract class AbstractHibernateDAO {

         protected SessionFactory sessionFactory;

         protected Session currentSession() {
             return sessionFactory.getCurrentSession();
         }
    }

Implementation of abstract class for entity user:

实体用户抽象类的实现:

@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);
    } 

}

}

And finally injecting right implementation:

最后注入正确的实现:

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