Spring 4 - Autowiring Issue: org.springframework.b

2019-08-26 01:19发布

问题:

Have a Spring MVC 4.0.3.RELEASE and (is not Spring Boot)...

This is actually a follow up to a previous post where a member told me to redesign a Spring MVC Controller and DAO relationship:

Spring 4 JDBC - How to load DB Properties and optimize (using Cache or DB Connection Pool)

Something is obviously not right:

pom.xml:

<properties>
    <java-version>1.7</java-version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <org-springframework-version>4.0.3.RELEASE</org-springframework-version>
</properties>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${org-springframework-version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${org-springframework-version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${org-springframework-version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${org-springframework-version}</version>
</dependency>

src/main/resources/sampledb.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <bean id="sampledb"  class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
        <property name="url"><value>jdbc:mysql://localhost/mydatabase?zeroDateTimeBehavior=convertToNull</value></property>
        <property name="username"><value>root</value></property>
        <property name="password"><value></value></property>
        <property name="maxIdle" value="10"/>
        <property name="maxActive" value="50"/>
        <property name="maxWait" value="100"/> 
        <property name="defaultAutoCommit" value="false"/>
        <property name="removeAbandoned" value="true"/>
        <property name="removeAbandonedTimeout" value="1"/>
        <property name="minIdle" value="0"></property>
        <property name="timeBetweenEvictionRunsMillis" value="1000"></property>
        <property name="minEvictableIdleTimeMillis" value="1000"></property>
     </bean> 
</beans>

WEB-INF/web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" 
         xmlns="http://java.sun.com/xml/ns/j2ee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>MyApp</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>      
</web-app>

WEB-INF/mvc-dispatcher-servlet.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <import resource="classpath:sampledb.xml" />
    <context:component-scan base-package="com.myapp.rest.controllers" />

    <mvc:annotation-driven />

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>

UserController:

package com.myapp.rest.controllers;

@Controller
@RequestMapping("/v2")
public class UserController {

    private final UserDAO dao;

    @Autowired
    public AppUserController(UserDao dao) {
        this.dao = dao;
    }

    @RequestMapping(value="appUsers/{userId}",method=RequestMethod.GET)
    public @ResponseBody Object getUserDetails(@PathVariable String userId) {
        Object response=null;
        response=dao.getUser(userId);
        return response;
    }
}

UserDao:

package com.myapp.rest.dao;

@Repository
@Service
public class UserDAO {

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public UserDao(@Qualifier("sampledb") DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    // others methods which do the actual queries using Spring JDBC
}

After copying the war into $CATALINA_HOME/webapps

Tomcat starts and throws this exception into stdout:

SEVERE: Context initialization failed
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController' defined in file [/opt/tomcat/apache-tomcat-7.0.78/webapps/MyApp/WEB-INF/classes/com/myapp/rest/controllers/UserController.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [com.myapp.rest.dao.UserDao]: : No qualifying bean of type [com.myapp.rest.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.myapp.rest.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.myapp.rest.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
    Jun 23, 2017 12:16:51 AM org.apache.catalina.core.ApplicationContext log
    SEVERE: StandardWrapper.Throwable
    org.springframework.beans.factory.UnsatisfiedDependencyException:Error creating bean with name 'userController' defined in file [/opt/tomcat/apache-tomcat-7.0.78/webapps/MyApp/WEB-INF/classes/com/myapp/rest/controllers/UserController.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [com.myapp.rest.dao.UserDao]: : No qualifying bean of type [com.myapp.rest.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.myapp.rest.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)

    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.myapp.rest.dao.UserDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
        ... 35 more

    Jun 23, 2017 12:16:51 AM org.apache.catalina.core.StandardContext loadOnStartup
    SEVERE: Servlet [mvc-dispatcher] in web application [/MyApp] threw load() exception
    org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.myapp.rest.dao.UserDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)

回答1:

See you haven't add package com.myapp.rest.dao to your component-scan, so that Spring could not know how to create UserDao object for your controllers

<context:component-scan base-package="com.myapp.rest.controllers" />

change to

<context:component-scan base-package="com.myapp.rest" />