2009-02-02 25 views
35

Tôi đang cố gắng sử dụng Spring IoC với một giao diện như thế này:Xuân IoC và Generic Interface Loại

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

Can Học Kỳ Mùa Xuân cung cấp IoC dựa vào loại lý luận chung T? Ý tôi là, một cái gì đó như thế này:

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

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

Tất nhiên, ví dụ của tôi ở trên không hoạt động:

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) 

Câu hỏi của tôi: là nó có thể cung cấp một chức năng tương tự với những thay đổi tối thiểu để một trong hai giao diện hoặc các lớp thực hiện? Tôi biết ví dụ tôi có thể sử dụng @Qualifiers, nhưng tôi muốn giữ mọi thứ càng đơn giản càng tốt.

+1

Nó có vẻ là có thể bây giờ kể từ mùa xuân 4.0. Xem [SO trả lời] này (http://stackoverflow.com/a/22603321/196533) và bài viết Spring có tiêu đề [Spring Framework 4.0 và Java Generics] (http://spring.io/blog/2013/12/03/spring-framework-4-0-and-java-generics). – chrisjleu

Trả lời

22

Tôi không tin rằng điều này là có thể do xóa. Chúng tôi thường chuyển sang gõ mạnh sub-interfaces khi đi cho toàn autowiring:

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

Bằng cách thực hiện chuyển đổi này, chúng tôi thấy chúng tôi thực sự thích điều này khá tốt, bởi vì nó cho phép chúng ta làm "tìm cách sử dụng" theo dõi tốt hơn nhiều, một cái gì đó bạn mất với giao diện generics.

+1

Và làm thế nào để bạn đối phó với sao chép mã? Có lẽ có một tầng lớp trung lưu cũng chung chung, phải không? Tks –

+0

Sự trùng lặp duy nhất cần thiết là giao diện điểm đánh dấu. Nhưng bạn không hiển thị các lớp triển khai của bạn vì vậy tôi không thể nói nếu bạn đang làm bất cứ điều gì tôi không nhìn thấy! – krosenvold

+0

Việc thực hiện sẽ phù hợp với một câu hỏi SO :) –

14

tôi không nghĩ rằng thats tốt mà không Qualifier

bệnh cố gắng để hiển thị Giải pháp của tôi với một genericDAO, xin lỗi nếu đó là một chút chi tiết

giao diện và lớp thực hiện 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; 
    } 

định nghĩa bean mùa xuân, hãy chú ý 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> 

Sử dụng genericDAO này mà không thực hiện đặc biệt lớp

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

thông báo constructor-arg với một lớp bê tông, nếu bạn làm việc với mùa xuân Chú bạn cần làm:

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

để phân biệt các phiên bản khác nhau của genericDao Beans (thông báo cho Qualifier với tham chiếu trực tiếp tới Beanname)

Sử dụng genericDAO này với việc thực hiện đặc biệt Lớp

giao diện và lớp

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

Định nghĩa Bean, chú ý đến "cha mẹ" Tham chiếu đến genericDAO trừu tượng trên

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

và sử dụng với mùa xuân Chú

@Autowired 
private TestHibernateParentDAO ToParentDAO; 
+0

Câu trả lời tuyệt vời đánh vào cả chú thích và sử dụng XML. Giải pháp này có hiệu quả cho bạn trong thời gian dài không? Trường hợp có bất kỳ hạn chế để sử dụng phương pháp này như có thể theo dõi thông qua mã dễ dàng hơn (đề cập bởi Krosenvold trong bài 1)? – HipsterZipster

+0

nó là một vấn đề về tổ chức/kiến ​​thức, nếu các nhà phát triển biết quy trình hoạt động, phương pháp chung này chắc chắn khó xử lý hơn việc sử dụng giao diện (điểm đánh dấu) –

3

Không làm cho giao diện của bạn chung chung.Thực hiện các phương pháp của bạn, thay vào đó:

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

Hy vọng điều đó sẽ hữu ích.

4

Có thể thực hiện việc này bằng cách xóa, nếu loại chung được hoàn toàn thống nhất vào thời gian biên dịch. Trong trường hợp này, thông tin loại có sẵn qua một trong hai:

Class#getGenericInterfaces() 
Class#getGenericSuperclass() 

Đây là tính năng chính của Guice bị thiếu trong Spring.

0

Khi thực hiện việc này với các lớp kiên trì nhất định, Spring Data sẽ thực hiện điều này cho bạn. Dữ liệu mùa xuân là một công cụ tiết kiệm và đơn giản hóa thời gian thực sự tuyệt vời nếu bạn đang sử dụng JPA, hoặc Neo4j, hoặc MongoDB, hoặc một cái gì đó khác mà nó hỗ trợ.

0

Một lựa chọn khác là để chú thích các giao diện thực hiện đậu với tên ở một bên và chú thích với vòng loại trỏ đến tên tạo ra ở phía bên kia :) Dưới đây là một ví dụ nhanh Tôi đang sử dụng trong dự án của tôi:

public interface IDAO<T> { 

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

lớp trừu tượng như người tiền nhiệm:

public abstract class AbstractHibernateDAO { 

     protected SessionFactory sessionFactory; 

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

thực hiện các lớp trừu tượng cho người sử dụng thực thể:

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

}

Và cuối cùng thực hiện đúng cách tiêm:

@Resource 
@Qualifier(value = "userRepository") 
IDAO<User> userPersistence; 
Các vấn đề liên quan