使用@Value注解注入配置在一些情况下是很笨重的,尤其是在多重配置或者垂直数据的情况下。Spring提供可选的方法,有力地归类配置到bean当中,以便管理和校验配置。

package com.example;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

@ConfigurationProperties("foo")
public class FooProperties {

    private boolean enabled;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    public boolean isEnabled() { ... }

    public void setEnabled(boolean enabled) { ... }

    public InetAddress getRemoteAddress() { ... }

    public void setRemoteAddress(InetAddress remoteAddress) { ... }

    public Security getSecurity() { ... }

    public static class Security {

        private String username;

        private String password;

        private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

        public String getUsername() { ... }

        public void setUsername(String username) { ... }

        public String getPassword() { ... }

        public void setPassword(String password) { ... }

        public List<String> getRoles() { ... }

        public void setRoles(List<String> roles) { ... }

    }
}

上面的POJO定义以下几个属性:

foo.enabled,默认false

foo.remote-address,可以从String强转的类型

foo.security.username,按某个规则确定的字符串

foo.security.password

foo.security.roles 一个String List

getter 和 setter 通常是必要的,绑定原理跟SpingMvc中数据绑定大致一样的,根据属性名绑定。但有时候也会setter也会被忽略的。

(1)Map,一开始初始化时候已经足够长了,因此只需要getter就行了。

(2)集合通常不用getter。

(3)如果一个普通POJO被初始化了,也不需要getter。

你还要通过@EnableConfigurationProperties注册属性类。

@Configuration
@EnableConfigurationProperties(FooProperties.class)
public class MyConfiguration {
}

当 @ConfigurationProperties 注解的bean注册之后,该bean将会有一个全名:<prefix>-<fqn>,<prefix>是@ConfigurationProperties注解中的prefix值,<fqn>是bean的类全名。如果该注解没有提供prefix,则只有类的全名,如foo-com.example.FooProperties

即使上面的配置创建了bean,我们要确定的是@ConfigurationProperties仅仅处理了Spring环境,特别是没从Context注入其他的Bean。@EnableConfigurationProperties注解同时会自动向应用提交申请,使得程序自动向环境中注入所有@ConfigurationProperties注解的Bena。你可以用快捷方式来保证FooProperties已经是个bean。

@Component
@ConfigurationProperties(prefix="foo")
public class FooProperties {

    // ... see above

}

利用配置文件

# application.yml

foo:
    remote-address: 192.168.1.1
    security:
        username: foo
        roles:
          - USER
          - ADMIN

# additional configuration as required

也通过可以在代码中注入Bean来实现

@Service
public class MyService {

    private final FooProperties properties;

    @Autowired
    public MyService(FooProperties properties) {
        this.properties = properties;
    }

     //...

    @PostConstruct
    public void openConnection() {
        Server server = new Server(this.properties.getRemoteAddress());
        // ...
    }

}

 1、第三方配置

和@ConfigurationProperties一样,你可以使用@Bean,这在你绑定属性值到你不能控制的第三方组件的时候很有用的。

添加配置@ConfigurationProperties到相应的Bean上,可以把环境属性配置到Bean。

@ConfigurationProperties(prefix = "bar")
@Bean
public BarComponent barComponent() {
    ...
}

任何配置在prefix=bar里面的属性都会映射到BarComponent对应的属性上。

2、轻松绑定

Spring Boot 使用众多轻松规则来绑定属性值到@ConfigurationProperties注解的beans,所以不需要匹配环境属性和Bean的属性。属性名通常由中线进行分割对应驼峰命名(context-path绑定到contextPath)。例如

@ConfigurationProperties(prefix="person")
public class OwnerProperties {

    private String firstName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

这些属性将会被用到:

person.firstName 标准驼峰命名

person.first-name  中线分割,要求在.properties和.yml文件中定义

person.first_name 下横线分割,要求在.properties和.yml文件中定义

PERSON_FIRST_NAME 大写字母,要求系统环境变量中定义

3、属性转换

Spring可以把外部应用的属性转换为正确的类型绑定到@ConfigurationProperties注解的Bean中。你可以提供一个ConversionService bean(id需为conversionService ),或者客户属性编辑器(一个CustomEditorConfigurer bean)或客户转化者(custom converters,带@ConfigurationPropertiesBinding注解的Bean)

4、@ConfigurationProperties校验

当注解了@ConfigurationProperties类添加了@Validated注解,Spring Boot会校验他。你可以引入JSR-303 javax.validation包,将其注解直接加到你配置的class的属性上。

@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {

    @NotNull
    private InetAddress remoteAddress;

    // ... getters and setters

}

对于对象属性,你可以添加@Valid,如

@ConfigurationProperties(prefix="connection")
@Validated
public class FooProperties {

    @NotNull
    private InetAddress remoteAddress;

    @Valid
    private final Security security = new Security();

    // ... getters and setters

    public static class Security {

        @NotEmpty
        public String username;

        // ... getters and setters

    }

}

你可以通过建立configurationPropertiesValidator bean来添加Spring Validator。@Bean方法应该定义为static,这样validator会率先创建(在应用生命周期之前),对相关bean进行初始化校验。

 5、@ConfigurationProperties vs @Value

@Value是核心容器注解且它不支持类型安全。下表显示两者区别。

Feature@ConfigurationProperties@Value

轻松绑定

Yes

No

Meta-data 支持

Yes

No

el表达式

No

Yes