代码之家  ›  专栏  ›  技术社区  ›  user1841495

Java Spring@Autowired未按预期工作

  •  3
  • user1841495  · 技术社区  · 8 年前

    由于@Autowired,我的应用程序未按预期运行。

    @PropertySource("WEB-INF/config.properties")
    public class DBQuery {
        @Autowired
        private Environment env;
    

    我已经尝试了许多可用的解决方案和示例两天了,但没有希望让我的应用程序正常运行。将非常感谢那些谁可以纠正我的代码。

    2016-12-15 14:23:04 WARN  XmlWebApplicationContext:487 - Exception encountered during context initialization - cancelling refresh attempt
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dbQuery' defined in ServletContext resource [/WEB-INF/test-servlet.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]: : No qualifying bean of type [java.lang.String] 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 [java.lang.String] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    

    尝试以下解决方案后更新了完整堆栈错误消息

    <bean id="dbQuery" class="com.cdmDP.db.DBQuery" >
        <constructor-arg type="java.lang.String" value="1"/>
    </bean>
    
    2016-12-15 15:46:49 ERROR ContextLoader:331 - Context initialization failed
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'DBQuery' defined in file [D:\program_files\apache-tomcat-8.0.39\webapps\test\WEB-INF\classes\com\test\db\DBQuery.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]: : No qualifying bean of type [java.lang.String] 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 [java.lang.String] 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:749)
            at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1139)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1042)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
            at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
            at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
            at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
            at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
            at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
            at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
            at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
            at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
            at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
            at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4853)
            at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5314)
            at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
            at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:753)
            at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:729)
            at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
            at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:940)
            at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1816)
            at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
            at java.util.concurrent.FutureTask.run(Unknown Source)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
            at java.lang.Thread.run(Unknown Source)
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] 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:1301)
            at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047)
            at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
            at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
            at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
            ... 28 more
    

    @Controller
    public class ViewAllData {
        DBQuery dbQuery;
    
        @Autowired
        public ViewAllData(DBQuery dbQuery){
            this.dbQuery = dbQuery;
        }
    
        @RequestMapping("/viewAllData")
        public ModelAndView viewData() throws SQLException, ClassNotFoundException{
            String dataTable;
            ResultSet rs = dbQuery.getAllData();
            //processing
    
            return new ModelAndView("viewAllData", "message", dataTable);
        }
    }
    

    com/test/db/DBQuery.java

    @Controller
    @Service
    @PropertySource("WEB-INF/config.properties")
    public class DBQuery {
        @Autowired
        private Environment env;
        String dbUsername = env.getProperty("db.username");
        String dbPassword = env.getProperty("db.password");
        String dbUrl = env.getProperty("db.url");
    
        String start;
        @Autowired
        public DBQuery(String start) throws ClassNotFoundException, SQLException{
            this.start = start;
        }
    
        public ResultSet getAllDataPassport() throws SQLException, ClassNotFoundException{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  
            Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
    
            Statement statement = conn.createStatement();
            String sql = "select * from testing_table";
            ResultSet rs = statement.executeQuery(sql);
    
            return rs;
        }
    
    }
    

    test-servlet.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"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans     
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context.xsd">
    
       <context:component-scan base-package="com.test, com.test.db" />
       <context:annotation-config />
    
        <bean id="viewAllData" class="com.test.ViewAllData"/>
        <bean id="dbQuery" class="com.test.db.DBQuery" >
            <property name="start" value="1"/>
        </bean>
    
        <bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource">
            <property name="basename" value="messages" />
        </bean>
    
        <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
            <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
            <property name="prefix" value="/WEB-INF/jsp/" />
            <property name="suffix" value=".jsp" />
        </bean>
    
    </beans>
    
    2 回复  |  直到 8 年前
        1
  •  3
  •   M. Deinum    8 年前

    您的代码在多方面存在缺陷。

    1. 由于不理解注释并将其与XML混合,您的配置存在缺陷
    2. 你应该使用 DataSource Connection 对象,并在使用后正确释放它们
    3. 控制器中不应该有SQL处理代码
    4. 您不应该在控制器中构造HTML

    您已经定义了 DBQuery 使用接受参数的构造函数初始化,您已使用 @Autowired 这意味着Spring将尝试创建 <context:component-scan /> )并尝试找到一个类型的bean String 在您的上下文中。那个豆子不在那里,所以它失败了。

    此外,您还将得到多个 数据库查询 由于组件扫描和您有一个XML的事实。删除XML配置。此外,组件可以是 @Service @Controller 但不是两者。和 @PropertySource @Configuration 这个班什么都不做。

    话虽如此,假设您主要希望首先使用注释,请删除 构造函数,只需创建 setStart 方法它更像是一个 @Repository 还有其他的。

    @Repository
    public class DBQuery {
    
        @Autowired
        private Environment env;
        String dbUsername = env.getProperty("db.username");
        String dbPassword = env.getProperty("db.password");
        String dbUrl = env.getProperty("db.url");
        String start; 
    
        public ResultSet getAllDataPassport() throws SQLException, ClassNotFoundException{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  
            Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
    
            Statement statement = conn.createStatement();
            String sql = "select * from testing_table";
            ResultSet rs = statement.executeQuery(sql);
    
            return rs;
        }
    }
    

    数据库查询 来自XML的bean以及 ViewAllData <上下文:组件扫描/>

    现在,不是使用 DriverManager 直接来说,您真的应该使用 数据来源 并将其注入到类中。

    <context:property-placeholder location="WEB-INF/config.properties" />
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
        <property name="url" value="${db.url}" />
        <property name="username" value="${db.username}" />
        <property name="password" value="${db.password}" />
    </bean>
    

    虽然 DriverManagerDataSource 数据来源 不要在生产中使用它。使用适当的连接池,如 HikariCP 那样的话这里的好处在于,您可以配置它,然后离开您的 数据库查询 照原样。

    现在,不是注射 Environment 所有属性都简单地注入 数据来源 进入 数据库查询 对象

    @Repository
    public class DBQuery {
    
        private final DataSource dataSource;
    
        @Autowired    
        public DBQuery(DataSource dataSource) {
            this.dataSource=dataSource;
        }
    
        public ResultSet getAllDataPassport() throws SQLException {
    
            Connection conn = this.dataSource.getConnection();
            Statement statement = conn.createStatement();
            String sql = "select * from testing_table";
            ResultSet rs = statement.executeQuery(sql);
            return rs;
        }
    }
    

    但是,此代码仍然有缺陷,因为您没有关闭 联系 ResultSet (除非你在你的控制器中这样做,这会使它更加有缺陷)。你的 getAllDataPassport 应该会返回一个 List 属于 Passport 对象(或 DataPassport ). 因此,您需要将控制器的部分处理/转换移动到 数据库查询 .

    为了使使用JDBC更容易,Spring提供了[ JdbcTemplate ]您可能希望使用它来编写代码,而不是 数据来源 因为这将为您管理资源关闭和异常处理。您可以很容易地使用 RowMapper 要将每行转换为 护照 对象

    在xml中添加以下内容

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
    

    把它注入你的 数据库查询 而不是 数据来源 .

    @Repository
    public class DBQuery {
    
        private final JdbcTemplate jdbcTemplate;
    
        @Autowired    
        public DBQuery(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    
        public List<Passport> getAllDataPassport() {
    
            String sql = "select * from testing_table";
            return this.jdbcTemplate.query(sql, new PassportRowMapper());
        }
    }
    

    上面的代码将执行查询,获取并关闭资源,并将行转换为 护照 对象当然,您需要编写 PassportRowMapper 要将每行转换为 护照 .

    public class PassportRowMapper implements RowMapper<Passport> {
    
        public Passport mapRow(ResultSet rs, int rowNum) throws SQLException {
            Passport p = new Passport();
            p.setNumber(rs.getString(1));
            // further logic to get row information
            return p;
        }
    }
    

    注: 不要这样做 rs.next 这个 使用 处理好了。您只需要将一行转换为 护照 .

    现在,您的控制器不再需要进行转换,不再与SQL绑定。对于测试,您现在可以轻松地模拟 数据库查询 并对您的 ViewAllData 控制器。

    @Controller
    public class ViewAllData {
    
        private final DBQuery dbQuery;
    
        @Autowired
        public ViewAllData(DBQuery dbQuery){
            this.dbQuery = dbQuery;
        }
    
        @RequestMapping("/viewAllData")
        public ModelAndView viewData() {
            String dataTable;
            List<Passport> passports = dbQuery.getAllDataPassports();
            // List to whatever it needs to be
            return new ModelAndView("viewAllData", "message", dataTable);
        }
    }
    

    在您的控制器中,看起来您正在转换 List<Passport 变成 我担心它包含一个HTML表。你不应该做这样的事情,你应该从属于你的角度来看待这个逻辑。

        @RequestMapping("/viewAllData")
        public ModelAndView viewData() {
            String dataTable;
            List<Passport> passports = dbQuery.getAllDataPassports();
            // List to whatever it needs to be
            return new ModelAndView("viewAllData", "passports", passports);
        }
    

    <table>
        <c:forEach items="${passports}" var="passport">
            <tr><td>${passport.number}</td><!-- other columns --></tr>
        </c:forEach>
    </table>
    

    现在,您已经解耦了视图、模型和控制器。现在,您甚至可以使用相同的控制器导出为PDF、Excel或JSON。而不改变它。

    最后提示:使用 InternalResourceViewResolver 而不是平原 UrlBasedViewResolver

    <bean id="viewResolver" class="org.springframework.web.servlet.view. InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
        2
  •  0
  •   Prakash Hari Sharma    8 年前

    问题在测试servlet中。对于xml dbQuery bean,请改用基于依赖项的构造函数”

    <bean id="dbQuery" class="com.test.db.DBQuery" >
        <property name="start" value="1"/>
    </bean>
    

    <bean id="dbQuery" class="com.test.db.DBQuery" >
        <constructor-arg type="java.lang.String" value="1"/>
    </bean>