Spring IoC и общий тип интерфейса
Я пытаюсь использовать Spring IoC с таким интерфейсом:
public interface ISimpleService<T> {
void someOp(T t);
T otherOp();
}
Может ли Spring предоставлять IoC на основе аргумента типового типа T? Я имею в виду, что-то вроде этого:
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, но я хочу, чтобы все было как можно проще.
Ответы
Ответ 1
Я не считаю, что это возможно из-за стирания. Обычно мы переходим к строго типизированным суб-интерфейсам при полнофункциональной автоподготовке:
public interface LongService extends ISimpleService<Long> {}
public interface StringService extends ISimpleService<String> {}
После этого мы обнаружили, что нам это очень понравилось, потому что это позволяет нам намного лучше отслеживать "поиск использования", что вы теряете с помощью интерфейсов generics.
Ответ 2
Я не думаю, что это возможно без Qualifier
плохо попробуйте показать мои решения с 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>
Обратите внимание на конструктор-arg с конкретным классом, если вы работаете с spring Аннотации, которую вам нужно сделать:
@Autowired
@Qualifier(value = "testHibernateChildDao")
private GenericDAO<TOChild, Integer> ToChildDAO;
чтобы различать различные версии genericDao Beans (обратите внимание на Qualifier с прямой ссылкой на Beanname)
Использование этого genericDAO со специальной реализацией 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 */
}
}
bean Определение, обратите внимание на "родительскую" ссылку на абстрактный genericDAO выше
<bean id="testHibernateParentDao" class="de.optimum24.av.pers.test.hibernate.dao.TestHibernateParentDAOImpl"
parent="genericHibernateDAO" />
и использование с помощью spring Аннотация
@Autowired
private TestHibernateParentDAO ToParentDAO;
Ответ 3
Это можно сделать с помощью стирания, если общий тип полностью подтвержден во время компиляции. В этом случае информация о типе доступна через любой из:
Class#getGenericInterfaces()
Class#getGenericSuperclass()
Это основная особенность Guice, которая отсутствует в Spring.
Ответ 4
Не делайте свой общий интерфейс. Вместо этого создайте свои методы:
public interface ISimpleService {
public <T> T doSomething(T param);
}
Надеюсь, что это поможет.
Ответ 5
При выполнении этого с некоторыми уровнями сохранения, Spring Данные делает это для вас. Spring Данные - действительно отличный инструмент для экономии времени и упрощения, если вы используете JPA, Neo4j или MongoDB, или что-то еще, что оно поддерживает.
Ответ 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;