对Spring ConfigurationProperties子类使用构造函数注入

时间:2018-08-10 15:59:45

标签: java spring dependency-injection immutability

我一直在看这个https://www.baeldung.com/configuration-properties-in-spring-boot,想知道是否可以对它们使用构造函数注入以强制执行某些不变性属性。

例如,可以这样做:

@Component
@ConfigurationProperties("my-config")
public class MyConfig {

    private final List<String> values;

    public MyConfig(@Value("${values}") List<String> values) {
        this.values = ImmutableList.copyOf(values);
    }
}

然后在我的yml配置中

my-config.values:
  - foo
  - bar

但是我得到这个错误:

java.lang.IllegalArgumentException: Could not resolve placeholder 'values' in string value "${values}"

5 个答案:

答案 0 :(得分:2)

documentation状态:

  

可以使用以下属性将属性值直接注入到您的bean中:   通过Spring的环境抽象访问的@Value注释,   通过@ConfigurationProperties 绑定到结构化对象。   :

您实际上尝试混合他们的行为。
values不是Spring环境的属性,而my-config.values是Spring环境的属性。
即使在MyConfig之内声明,例如@Value("${values})",它也不会改变任何内容,因为@ConfigurationProperties会将属性绑定到结构化对象。当然,它不会在Spring环境中创建新属性,这是@Value()寻求解析值表达式的地方。
而解决${values}的异常。

由于MyConfig是组件@Value应该是您所需要的:

@Component
public class MyConfig {

    private final List<String> values;

    public MyConfig(@Value("${my-config.values}") List<String> values) {
        this.values = ImmutableList.copyOf(values);
    }
}

您也可以通过检查设置器来防止可变性,但这只会在运行时检测到问题:

@ConfigurationProperties("my-config")
public class MyConfig {

    private final List<String> values;

    public List<String> getValue(){
         return values;
    }
    public void setValue(List<String> values){  
         if (this.values != null){
             throw new IllegalArgumentException("...");
         }                    
         this.values = ImmutableList.copyOf(values);
    }
}

答案 1 :(得分:1)

对于@ConfigurationProperties,spring仅使用属性(或setter)注入。因此,该类应该是可变的。

在这种情况下,也不必具有构造函数(也可以跳过@Value注释),并且类可以像这样简单:

@Component
@ConfigurationProperties("my-config")
public class MyConfig {

   private List<String> values;
   //getter+setter
}

答案 2 :(得分:1)

春季启动可以使用

,因为版本2.2.0文档在此处:Constructor binding添加新的注释 @ConstructorBinding

答案 3 :(得分:0)

删除@Value("${values}"),仅使用 getters / setters
或使用 SpEL -@Value("#{'${my-second-config.values}'.split(',')}"

还要看一下Spring boot documentation
下面的示例:

@SpringBootApplication
public class DemoApplication {

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

@Component
@ConfigurationProperties("my-config")
public static class MyConfig {

    private List<String> values;

    public List<String> getValues() {
        return values;
    }

    public void setValues(List<String> values) {
        this.values = ImmutableList.copyOf(values);
    }
}

@Configuration
public static class MySecondConfig {

    private final List<String> values;

    @Autowired
    public MySecondConfig(@Value("#{'${my-second-config.values}'.split(',')}") 
                                 List<String> values) {
        this.values = ImmutableList.copyOf(values);
    }

    public List<String> getValues() {
        return values;
    }
}

@Service
public static class MyService {

    private final MyConfig myConfig;
    private final MySecondConfig mySecondConfig;

    @Autowired
    public MyService(MyConfig myConfig, MySecondConfig mySecondConfig) {
        this.myConfig = myConfig;
        this.mySecondConfig = mySecondConfig;
    }

    @PostConstruct
    public void startUp() {
        myConfig.getValues().forEach(System.out::println);
        mySecondConfig.getValues().forEach(System.out::println);
    }

}

}

application.properties

my-config.values[0]=a
my-config.values[1]=b
my-second-config.values=c,d

控制台输出:
    a
    b
    c
    d

答案 4 :(得分:0)

@ConfigurationProperties将值与给定前缀绑定。 @ConfigurationProperties和@Value无关。因此,@ value将不是您在@ConfigurationProperties中提到的路径的相对路径。 此外,@ConfigurationProperties还使用setter来注入值,如果您希望使属性不可变,则必须以某种方式对setter进行调整。

public void setProperty(String property){
if(this.property == null){
this.property = property;
}
}