我正在编写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模式,除非你们告诉我这是一个很糟糕的想法。
提前感谢你们给我的任何帮助!
答案 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);
}
}