【问题标题】:NoSuchBeanDefinitionException Spring 3.2.2 Hibernate 4 using annotation configuration building with Maven 3NoSuchBeanDefinitionException Spring 3.2.2 Hibernate 4 使用注释配置构建与 Maven 3
【发布时间】:2013-10-02 16:23:09
【问题描述】:

我错过了什么? 我正在尝试使用 Hibernate 创建一个基本的 SpringMVC 应用程序。我有另一个 SpringMVC 应用程序,我对其进行建模并且它可以工作。 我显然错过了一些东西,我不知所措。在这里的任何帮助将不胜感激。只需另一双眼睛就可以解决问题。可能是我瞎了。

基本上,错误告诉我无法在控制器中创建 customerService bean,因为无法定位 customerDao bean,因此无法将其注入服务。

当我使用 Intellij 时,我能够遵循 bean 引用并且一切都出现了 要正确连接,但是当我在 tomcat6 或 tomcat7 中运行时出现以下错误:

Sep 26, 2013 10:13:02 AM org.springframework.web.context.ContextLoader initWebApplicationContext
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mydomain.dao.CustomerDao com.mydomain.service.CustomerService.customerDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mydomain.dao.CustomerDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1122)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4701)
        at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5204)
        at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5199)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
        at java.util.concurrent.FutureTask.run(FutureTask.java:166)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:724)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mydomain.dao.CustomerDao com.mydomain.service.CustomerService.customerDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mydomain.dao.CustomerDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
        ... 21 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mydomain.dao.CustomerDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:856)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
        ... 23 more
Sep 26, 2013 10:13:02 AM org.apache.catalina.core.StandardContext startInternal

代码如下:

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.mydomain.config.WebConfig</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.mydomain.config.WebConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

WebConfig.java

package com.mydomain.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;


@EnableWebMvc
@Configuration
@Import({DaoConfig.class, ServiceConfig.class, ControllerConfig.class})
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public Validator getValidator(){
        return new LocalValidatorFactoryBean();
    }

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setViewClass(JstlView.class);
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");

        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

DaoConfig.java

package com.mydomain.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan({"com.mydomain.dao", "com.mydomain.service"})
public class DaoConfig {
    @Bean
    public LocalSessionFactoryBean getSessionFactory(){
        final LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(getDataSource());
        sessionFactoryBean.setPackagesToScan(new String[]{"com.mydomain.domain"});
        sessionFactoryBean.setHibernateProperties(hibernateProperties());
        return sessionFactoryBean;
    }

    @Bean
    public DataSource getDataSource(){
        final DriverManagerDataSource dmds = new DriverManagerDataSource();
        dmds.setDriverClassName("com.mysql.jdbc.Driver");
        dmds.setUsername("root");
        dmds.setPassword("");
        dmds.setUrl("jdbc:mysql://localhost/commandsearch");
        return dmds;
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        final HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(getSessionFactory().getObject());

        return txManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    final Properties hibernateProperties() {
        return new Properties() {
            {
                setProperty("hibernate.hbm2ddl.auto", "update");
                setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                setProperty("hibernate.show_sql", "true");
            }
        };
    }
}

IAbstractDao.java

package com.mydomain.dao;

import java.io.Serializable;
import java.util.List;

public interface IAbstractDao <T extends Serializable> {
    T findOne(final long id);
    List<T> findAll();
    void save(final T t);
    void delete(final T t);
    void deleteById(final long id);
}

AbstractHibernateDao.java

package com.mydomain.dao;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class AbstractHibernateDao<T extends Serializable> implements IAbstractDao<T> {
    protected Class<T> entityClass;
    protected final Log logger = LogFactory.getLog(getClass()); 

    protected AbstractHibernateDao(Class<T> entityClass){
        this.entityClass = entityClass;
    }

    @Autowired
    private SessionFactory sessionFactory;

    protected final Session getCurrentSession(){
        return sessionFactory.getCurrentSession();
    }
    @Override
    public T findOne(final long id) {
        return ((T) getCurrentSession().get(entityClass, id));
    }

    @Override
    public List<T> findAll() {
        return (List<T>)getCurrentSession().createQuery("from " + entityClass.getName()).list();
    }

    @Override
    public void save(final T t) {
        getCurrentSession().saveOrUpdate(t);
    }

    @Override
    public void delete(final T t) {
        getCurrentSession().delete(t);
    }

    @Override
    public void deleteById(final long id) {
        final T entity = findOne(id);
        delete(entity);
    }
}

CustomerDao.java

package com.mydomain.dao;

import org.springframework.stereotype.Repository;

import com.mydomain.domain.Customer;

@Repository
public class CustomerDao extends AbstractHibernateDao<Customer> {
    public CustomerDao(){
        this(Customer.class);
    }

    public CustomerDao(Class<Customer> entityClass){
        super(entityClass);
    }
}

ServiceConfig.java

package com.mydomain.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({"com.mydomain.service"})
public class ServiceConfig {

}

AbstractService.java

package com.mydomain.service;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;

import com.mydomain.dao.IAbstractDao;

@Transactional
public abstract class AbstractService<T extends Serializable> {
    protected final Log logger = LogFactory.getLog(getClass());

    public T findOne(final long id) {
        return getDao().findOne(id);
    }

    public List<T> findAll() {
        return getDao().findAll();
    }

    public void save(final T entity) {
        getDao().save(entity);
    }

    public void delete(final T entity) {
        getDao().delete(entity);
    }

    public void deleteById(final long entityId) {
        getDao().deleteById(entityId);
    }

    protected abstract IAbstractDao<T> getDao();
}

客户服务.java

package com.mydomain.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mydomain.dao.CustomerDao;
import com.mydomain.dao.IAbstractDao;
import com.mydomain.domain.Customer;

@Service
@Transactional
public class CustomerService extends AbstractService<Customer>{

    @Autowired
    private CustomerDao customerDao;

    @Override
    protected IAbstractDao<Customer> getDao() {
        return customerDao;
    }
}

【问题讨论】:

  • 您应该拆分配置,目前您正在复制所有 bean 实例,因为 ContextLoaderListenerDispatcherServlet 加载相同的配置。

标签: spring hibernate spring-mvc autowired spring-annotations


【解决方案1】:

你的直接问题是这样的

package com.mydomain.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({"com.mydomain.service"})
public class ServiceConfig {

}

您正在扫描您的 @Service 类,但您在 那个 上下文中没有任何内容可以为您提供可用于注入的 CustomerDao bean,因此它会失败,除非您有异常。


您的配置还有很多其他问题。您的 DaoConfig 扫描 daoservice 包。这本身还不错,但是您拥有所有其他多余的 XConfig 类。

另外,您的web.xml 配置将创建2 个WebConfig 上下文,一个用于DispatcherServlet,一个用于ContextLoaderListener

您的ContextLoaderListener 应该加载根上下文DispatcherServlet 应该加载servlet 上下文

例如,DispatcherServlet 应该像这样加载WebConfig

@EnableWebMvc
@Configuration
@Import(ControllerConfig.class)
public class WebConfig extends WebMvcConfigurerAdapter {

请注意@Imports ControllerConfig

您的ContextLoaderListener 应该像这样加载应用程序配置

@Configuration
@EnableTransactionManagement
@ComponentScan({"com.mydomain.dao", "com.mydomain.service"}, ...)
public class ApplicationConfig {
    // all the @Bean methods from each of your other XxxConfig classes
}

如果您想进一步模块化它,请记住 @Import 仅适用于使用它的 @Configuration 类或上下文,而不适用于正在导入的上下文。

【讨论】:

  • DaoConfig 正在扫描 com.mydomain.dao 包,它应该创建 CustomerDao bean。我不需要 ServiceConfig 中的引用。 CustomerService 类具有对 CustomerDao 的 Autowire 引用。至于 DaoConfig 扫描这两个包,我尝试过扫描服务包和不扫描服务包。我有这个 web.xml 在不同的应用程序中工作,但差异很小。我不记得为什么我这样做了,但是在另一个应用程序中都需要一些东西
  • @John 牛肉是DaoConfig 正在使用@Import(ServiceConfig.class),它试图加载一个带有@Service 类的上下文,该类需要注入一个不存在的CustomerDao bean 那个上下文。您的上下文配置不正确。仔细阅读我的回答。
  • 我不确定 DaoConfig 如何使用 @Import(ServiceConfig.class) WebConfig 正在执行所有导入,并且每个配置都在处理自己的 ComponentScan。我有这个设置在另一个应用程序中工作。我在其他应用程序中的唯一区别是每个 dao 都有一个接口。我在这里跳过了。 Intellij 能够遵循 IDE 中的 bean 声明。我确实尝试过拆分 ContextLoader 和 DispatchServlet,我只是想避免声明每个 bean。
  • @John 我的错,你的WebConfig 正在这样做。
猜你喜欢
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-25
  • 2011-02-13
  • 2015-05-06
相关资源
最近更新 更多