簡體   English   中英

Spring 3.2 Autowire泛型類型

[英]Spring 3.2 Autowire generic types

所以我在Spring 3.2中有很多泛型,理想情況下我的架構看起來像這樣。

class GenericDao<T>{}

class GenericService<T, T_DAO extends GenericDao<T>>
{
    // FAILS
    @Autowired
    T_DAO;
}

@Component
class Foo{}

@Repository
class FooDao extends GenericDao<Foo>{}

@Service
FooService extends GenericService<Foo, FooDao>{}

遺憾的是,對於泛型的多個實現,自動裝配會引發有關多個匹配bean定義的錯誤。 我認為這是因為@Autowired進程在類型擦除之前。 我找到或想出的每一個解決方案看起來都很難看,或者只是莫名其妙地拒絕工作。 解決這個問題的最佳方法是什么?

如何將構造函數添加到GenericService並將自動裝配移動到擴展類,例如

class GenericService<T, T_DAO extends GenericDao<T>> {
    private final T_DAO tDao;

    GenericService(T_DAO tDao) {
        this.tDao = tDao;
    }
}

@Service
FooService extends GenericService<Foo, FooDao> {

    @Autowired
    FooService(FooDao fooDao) {
        super(fooDao);
    }
}

更新:

Spring 4.0 RC1開始 ,可以基於泛型類型進行自動裝配,這意味着您可以編寫類似的通用服務

class GenericService<T, T_DAO extends GenericDao<T>> {

    @Autowired
    private T_DAO tDao;
}

並創建多個不同的Spring bean,如:

@Service
class FooService extends GenericService<Foo, FooDao> {
}

您可以使用@PostConstruct和ServiceLocatorFactoryBean刪除@autowire注釋並執行延遲的“autowire”。
您的GenericService看起來與此類似

    public class GenericService<T, T_DAO extends GenericDao<T>>{

        @Autowired
        private DaoLocator daoLocatorFactoryBean;

        //No need to autowried, autowireDao() will do this for you 
        T_DAO dao;


        @SuppressWarnings("unchecked")
        @PostConstruct
        protected void autowireDao(){
        //Read the actual class at run time
        final Type type; 
        type = ((ParameterizedType) getClass().getGenericSuperclass())
                                              .getActualTypeArguments()[1]; 
        //figure out the class of the fully qualified class name
        //this way you can know the bean name to look for
        final String typeClass = type.toString();      
        String daoName = typeClass.substring(typeClass.lastIndexOf('.')+1
                                            ,typeClass.length());
        daoName = Character.toLowerCase(daoName.charAt(0)) + daoName.substring(1);
        this.dao = (T_DAO) daoLocatorFactoryBean.lookup(daoName);
       }

daoLocatorFactoryBean為您帶來了魔力。
要使用它,您需要添加類似下面的界面:

 public interface DaoLocator {
        public GenericDao<?> lookup(String serviceName);           
 }    

您需要將以下代碼段添加到applicationContext.xml中

  <bean id="daoLocatorFactoryBean" 
      class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
      <property name="serviceLocatorInterface"
              value="org.haim.springframwork.stackoverflow.DaoLocator" />
    </bean>

這是一個很好的技巧,它將為您節省很少的樣板類。
順便說一句,我不認為這個樣板代碼是一個大問題,我工作的項目使用matsev方法。

這是最接近的解決方案。 專業DAO在業務層注釋。 與OP的問題一樣,最好的努力是在EntityDAO通用模板本身中使用帶注釋的DAO。 類型擦除似乎不允許將專用類型信息傳遞到spring工廠[導致報告來自所有專用DAO的匹配bean]

通用實體DAO模板

public class EntityDAO<T> 
{
    @Autowired
    SessionFactory factory;

    public Session getCurrentSession()
    {
        return factory.getCurrentSession();
    }

    public void create(T record)
    {
        getCurrentSession().save(record);
    }

    public void update(T record)
    {
        getCurrentSession().update(record);
    }

    public void delete(T record)
    {
        getCurrentSession().delete(record);
    }

    public void persist(T record)
    {
        getCurrentSession().saveOrUpdate(record);
    }

    public T get(Class<T> clazz, Integer id)
    {
        return (T) getCurrentSession().get(clazz, id);
    }
}

基於通用實體的業務層模板

public abstract class EntityBusinessService<T>
implements Serializable
{
    public abstract EntityDAO<T> getDAO();

    //Rest of code.
}

示例專用實體DAO

@Transactional
@Repository
public class UserDAO
extends EntityDAO<User>
{
}

一個示例專業實體商務類

@Transactional
@Service
@Scope("prototype")
public class UserBusinessService
extends EntityBusinessService<User>
{
    @Autowired
    UserDAO dao;

    @Override
    public EntityDAO<User> getDAO() 
    {
        return dao;
    }

    //Rest of code
}

為什么要通用服務? 服務類適用於涉及多個實體的特定工作單元。 您可以直接將存儲庫注入控制器。

下面是一個帶有構造函數參數的通用存儲庫的示例,您也可以將每個方法設置為Generic而不具有構造函數參數。 但是每個方法調用都需要class作為參數:

public class DomainRepository<T> {

   @Resource(name = "sessionFactory")
   protected SessionFactory sessionFactory;

   public DomainRepository(Class genericType) {
        this.genericType = genericType;
   }

   @Transactional(readOnly = true)
   public T get(final long id) {
       return (T) sessionFactory.getCurrentSession().get(genericType, id);
   }

通用存儲庫的bean定義示例 - 您可以使用不同的contstructor args來擁有多個不同的bean。

<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
        <constructor-arg value="com.yourcompnay.domain.Tag"/>
</bean>

使用資源注釋實現bean的Depdncy注入

@Resource(name = "tagRepository")
private DomainRepository<Tag> tagRepository;

這樣就可以將Domainreposiroty子類化為特定的實體/方法,這些實體/方法不會自動裝配:

public class PersonRepository extends DomainRepository<Person> {
    public PersonRepository(){
        super(Person.class);
    }
    ...

對於這個問題,我們需要了解autowire是什么。 通常我們可以說,通過autowire,我們在部署Web應用程序時創建了一個對象實例/ bean。 因此,如果您在同一個名稱的多個地方聲明自動裝配,那么現在回答這個問題。 然后出現這個錯誤。 自動裝配可以通過多種方式完成,因此如果您使用多種類型的自動裝配技術,那么也可能會出現此錯誤。

您應該在擴展這些泛型的類中使用自動裝配

使用Spring 4完成通用解決方案:


域類

@Component
class Foo{
}

@Component
class Bar{
}

DAO層

interface GenericDao<T>{
//list of methods
}

class GenericDaoImpl<T> implements GenericDao<T>{
 @Autowired
 SessionFactory factory;

 private Class<T> domainClass; // Get Class Type of <T>

 public Session getCurrentSession(){
    return factory.getCurrentSession();
 }

 public DaoImpl() {
    this.domainClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), DaoImpl.class);
 }
 //implementation of methods
}

interface FooDao extends GenericDao<Foo>{
//Define extra methods if required
}

interface BarDao extends GenericDao<Bar>{
//Define extra methods if required
}

@Repository
class FooDao extends GenericDaoImpl<Foo> implements FooDao{
 //implementation of extra methods
}

@Repository
class BarDao extends GenericDaoImpl<Bar> implements BarDao{
 //implementation of extra methods
}

服務層

interface GenericService<T>{
//List of methods
}

class GenericServiceImpl<T> implements GenericService<T>{
 @Autowire
 protected GenericDao<T> dao; //used to access DAO layer
}

class FooService extends GenericService<Foo>{
//Add extra methods of required
}

class BarService extends GenericService<Bar>{
//Add extra methods of required
}

@Service
class FooServiceImpl extends GenericServiceImpl<Foo> implements GenericService<Foo>{
//implementation of extra methods
}

@Service
class BarServiceImpl extends GenericServiceImpl<Bar> implements GenericService<Bar>{
//implementation of extra methods
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM