通用Dao,服务层和多个匹配bean

时间:2013-11-04 22:27:43

标签: spring-mvc hibernate-generic-dao

我正在编写Spring MVC 3.2.3和Hibernate 4.2.1应用程序,只是启动它的架构。我决定使用Generic Dao模式,因为我将使用许多常见的CRUD操作。我知道JPA已经存在了一段时间,但我真的很想用通用的dao模式实现这一点。    自己的问题。在设置和测试WITH ONE ENTITY时,一切都很顺利。但是当我添加第二个时,我开始看到错误:

“没有定义[com.segurosweb.daos.GenericDao]类型的限定bean:期望的单个匹配bean但找到2:cobradorDaoImpl,productorDaoImpl”。

据我所知,这是因为Spring在启动时无法判断要注入哪个组件,但我不知道如何解决这个问题。

我使用的通用DAO实现是:

GenericDao.java

package com.segurosweb.daos;

import java.util.List;

public interface GenericDao<T> {

    public void saveOrUpdate(T dom);
    public List<T> getAll();
    public T get(long id);

}

GenericDaoImpl.java

package com.segurosweb.daos;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@SuppressWarnings("unchecked")
@Repository
public abstract class GenericDaoImpl<T> implements GenericDao<T>{

    private Class<T> type;

    @Autowired
    private SessionFactory sessionFactory;

    @SuppressWarnings("rawtypes")
    public GenericDaoImpl(){
        Type t = getClass().getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType) t;
        type = (Class) pt.getActualTypeArguments()[0];
    }


    public Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }
... all other implementation...
}

CobradorDao.java

package com.segurosweb.daos;

import com.segurosweb.entities.Cobrador;

public interface CobradorDao extends GenericDao<Cobrador>{

}

CobradorDaoImpl.java

package com.segurosweb.daos;

import org.springframework.stereotype.Repository;

import com.segurosweb.entities.Cobrador;

@Repository
public class CobradorDaoImpl extends GenericDaoImpl<Cobrador> implements CobradorDao{

}

GenericService.java

package com.segurosweb.service;

import java.util.List;

public interface GenericService<T> {

    public void saveOrUpdate(T dom);
    public List<T> getAll();
    public T get(long id);

}

GenericServiceImpl.java

package com.segurosweb.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.segurosweb.daos.GenericDao;

public class GenericServiceImpl<T> implements GenericService<T>{

    @Autowired
    private GenericDao<T> tDao;

    @Override
    public void saveOrUpdate(T dom) {
        tDao.saveOrUpdate(dom);     
    }

    @Override
    public List<T> getAll() {
        return tDao.getAll();
    }

    @Override
    public T get(long id) {
        return tDao.get(id);
    }

}

CobradorService.java

package com.segurosweb.service;

import com.segurosweb.entities.Cobrador;

public interface CobradorService extends GenericService<Cobrador>{

}

CobradorServiceImpl.java

package com.segurosweb.service;

import org.springframework.stereotype.Service;

import com.segurosweb.entities.Cobrador;

@Service
public class CobradorServiceImpl extends GenericServiceImpl<Cobrador> implements CobradorService{

}

我的控制器,它有一个非常简单的网址映射来测试每一个都可以工作(或者没有!)

package com.segurosweb.controllers;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.segurosweb.entities.Cobrador;
import com.segurosweb.service.CobradorService;

@Controller
@RequestMapping("/cobradores/**")
public class CobradorController {

    static final Logger log = LogManager.getLogger(CobradorController.class.getSimpleName());

    @Autowired
    private CobradorService cobServ;

    @RequestMapping(value="view.html",method = RequestMethod.GET)
    public ModelAndView setUpForm(ModelMap model){  

        log.info("cobradores/view.html hitted.");
        cobServ.saveOrUpdate(new Cobrador("emi","lio","hola","321"));       
        return new ModelAndView("/secure/Productores");

    }

}

Cobrador.java是一个非常简单的用@Entity注释的POJO类。

我还有另一个实体的匹配接口和实现,名为Productor:ProductorDao,ProductorDaoImpl,ProductorService和ProductorServiceImpl。

我得到的确切错误是:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cobradorController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.segurosweb.service.CobradorService com.segurosweb.controllers.CobradorController.cobServ; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cobradorServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.segurosweb.daos.GenericDao com.segurosweb.service.GenericServiceImpl.tDao; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.segurosweb.daos.GenericDao] is defined: expected single matching bean but found 2: cobradorDaoImpl,productorDaoImpl

那么,我错过了一些重要的东西吗?我现在想坚持使用这种通用DAO模式,除非你们告诉我这是一个很糟糕的想法。

提前感谢你们给我的任何帮助!

3 个答案:

答案 0 :(得分:3)

对于初学者,我会删除Generic DAO并切换到Spring Data JPA,不要试图重新发明轮子,这样就可以避免编写另一种内部框架。

关于通用服务,或者更好的服务方法,一对一调用你的dao上的相应方法,这就是imho,一种设计气味。您的服务应提供业务案例/用例来解决。像saveOrUpdate这样的方法并不具有商业意义。在那些情况下,我可能会直接调用存储库(只是为了图层添加另一个层是不明智的imho)。

有一个问题/博客基本上得出了相同的结论(我再也找不到了,是Spring Data JPA的维护者Oliver Gierke的评论。

问题是4.0之前的Spring版本存在依赖注入和通用接口的问题,这在Spring 4.0中已经solved

链接:

答案 1 :(得分:2)

在Spring 3x版本中,即使您使用了泛型类型,也无法识别相应的bean。 Spring 4已经解决了这个bug。所以根据我的说法,你必须使用@Qualifier注释来告诉spring容器你要注入哪个具有相同父类型的bean。

@Repository("cobradorDao")

@Repository("productorDao")

@Autowire
@Qualifier("cobradorDao")
CobradorDao cobradorDao;

@Autowire
@Qualifier("productorDao")
ProductorDao productorDao;

我希望对你有所帮助。

答案 2 :(得分:0)

您应该遵守本准则。

GenericServiceImpl.java

package com.segurosweb.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.segurosweb.daos.GenericDao;

public class GenericServiceImpl<T> implements GenericService<T>{


    private GenericDao<T> tDao;

    public GenericServiceImpl(GenericDao<T> tDao) {
        this.tDao= tDao;
    }

    @Override
    public void saveOrUpdate(T dom) {
        tDao.saveOrUpdate(dom);     
    }

    @Override
    public List<T> getAll() {
        return tDao.getAll();
    }

    @Override
    public T get(long id) {
        return tDao.get(id);
    }

}

CobradorServiceImpl.java

package com.segurosweb.service;

import org.springframework.stereotype.Service;

import com.segurosweb.entities.Cobrador;

@Service
public class CobradorServiceImpl extends GenericServiceImpl<Cobrador> implements CobradorService{

    @Autowired
    public CobradorServiceImpl(CobradorDao tDao) {
      super(tDao);
    }

}