【问题标题】:Generic Dao, service layer and multiple matching beans泛型 Dao、服务层和多个匹配的 bean
【发布时间】:2013-11-15 16:58:32
【问题描述】:

我正在编写一个 Spring MVC 3.2.3 和 Hibernate 4.2.1 应用程序,刚刚开始它的架构。我决定使用 Generic Dao 模式,因为我将使用很多常见的 CRUD 操作。我知道 JPA 已经存在了一段时间,但我真的很想使用通用 dao 模式来实现这一点。 对于问题本身。使用一个实体进行设置和测试时一切正常。但是当我添加第二个时,我开始看到错误:

“没有定义 [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{

}

还有我的控制器,它有一个非常简单的 url 映射来测试一切是否正常工作(或不工作!)

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 是一个非常简单的 POJO 类,使用 @Entity 注解。

我还有另一个实体的匹配接口和实现,称为 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 模式,除非你们告诉我这是非常糟糕的主意。

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

【问题讨论】:

    标签: spring-mvc hibernate-generic-dao


    【解决方案1】:

    对于初学者,我会放弃通用 DAO 并切换到 Spring Data JPA,不要尝试重新发明轮子,这样你就不用编写另一种内部框架了。

    关于通用服务,或者更好的服务方法,通常一对一地调用你的 dao 上的相应方法,恕我直言,这是一种设计味道。您的服务应提供要解决的业务案例/用例。像saveOrUpdate 这样的方法并不是真正具有商业意义的东西。在这些情况下,我可能会直接调用存储库(仅仅为了该层而添加另一层是不明智的恕我直言)。

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

    问题是Spring 4.0之前的版本存在依赖注入和泛型接口的问题,这个在Spring 4.0中一直是solved

    链接:

    【讨论】:

    • 我阅读了更多关于 Spring Data JPA 的内容,你说得对,通用 DAO “嵌入”了。我还检查了 Spring 4.0,事实上,它对注入泛型接口的方式进行了更正。所以这个事实将我的设计问题减少到 2 个选项,移动到 Spring Data JPA,或者等待 Spring 4.0 发布。非常感谢。
    【解决方案2】:

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

    @Repository("cobradorDao")
    
    @Repository("productorDao")
    
    @Autowire
    @Qualifier("cobradorDao")
    CobradorDao cobradorDao;
    
    @Autowire
    @Qualifier("productorDao")
    ProductorDao productorDao;
    

    希望对你有帮助。

    【讨论】:

      【解决方案3】:

      你应该被这个守则修复。

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

      【讨论】:

        猜你喜欢
        • 2013-05-27
        • 2017-06-07
        • 2013-05-16
        • 1970-01-01
        • 1970-01-01
        • 2012-11-26
        • 2014-08-15
        • 2011-04-19
        • 2011-08-23
        相关资源
        最近更新 更多