Spring无法自动注入构造函数参数

时间:2017-08-21 10:20:08

标签: java spring spring-boot dependency-injection configuration

我是一个完整的Spring初学者,我正在尝试使用Spring Boot进行基本配置。我想尽可能使用构造函数注入。但是,Spring正在抛出我不理解的异常。我缩短了有问题的代码以便于阅读:

我的配置YAML文件(我在类路径上有蛇yaml):

database:
    inactive_timeout: 100
    active_jdbc_connections:
        # this is a list with one property in each element
        - name: foo
        - name: bar
        - name: baz
        - name: qux

申请代码:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    private final DBProperties dbProperties;
    DBProperties getDbProperties() {
        return dbProperties;
    }

    public DemoApplication(DBProperties dbProperties) {
        this.dbProperties = dbProperties;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Spring没有正确连接的类:

package com.example.demo;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;

@ConfigurationProperties(prefix = "database")
@Component
public class DBProperties {
    private final List<ConnectionProperties> activeJdbcConnections;
    private int inactiveTimeout;

    // ERROR: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'int' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    public DBProperties(List<ConnectionProperties> activeJdbcConnections, int inactiveTimeout) {
        this.activeJdbcConnections = activeJdbcConnections;
        this.inactiveTimeout = inactiveTimeout;
    }

    public List<ConnectionProperties> getActiveJdbcConnections() {
        return activeJdbcConnections;
    }

    public int getInactiveTimeout() {
        return inactiveTimeout;
    }

    @Component
    public static class ConnectionProperties {
        private String name;

        // ERROR: Parameter 0 of constructor in com.example.demo.DBProperties$ConnectionProperties required a bean of type 'java.lang.String' that could not be found.
        public ConnectionProperties(String name){
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }
}

有两个单独的错误。首先,在DBProperties构造函数中,Spring无法连接整数inactiveTimeout,即使它在连接参数activeJdbcConnections时也没有问题。这可以使用@Value参数来解决,但这是不可取的,因为@Value不能识别@ConfigurationParameters指定的前缀,因此必须为每个@Value注释重复前缀。

其次,Spring无法连接name的{​​{1}}参数。如果添加了Spring,Spring可以使用setter,但如上所述,我想使用构造函数注入。由于参数的名称与我想要连接的属性匹配,我不明白这里的问题。作为旁注,我无法用@Value注释来解决这个问题,因为我不知道从当前列表元素中指定属性的语法。

如何让Spring使用构造函数注入来正确实例化我的配置类?

1 个答案:

答案 0 :(得分:1)

我认为您的方法存在一些问题。首先,您不能定义int和String类型的bean(即使您尝试在某处定义它们),因此名称和inactiveTimeout将永远不可用作通过构造函数注入自动装配的bean。

其次,@Components在扫描时默认为Spring单例bean,这意味着每个Spring上下文只有一个实例。如果你将它传递给DBProperties构造函数的列表,那么将ConnectionProperties作为一个组件就没那么有意义,因为只有一个实例化的ConnectionProperties,所以它有点像一个短列表!

如果您希望DBProperties是一个在其构造函数中提供了一些参数的bean,那么您可能希望直接将其定义为@Bean并自己调用构造函数。 Spring无法确定你想要放在哪里的参数!类似的东西:

@Bean
public DBProperties dbProperties() {
    ...
    return new DBProperties(myArray, myNumber);
}

然后,这个DBProperties bean可以在Spring启动应用程序的其他任何地方注入Constructor。