CH11-配置绑定
使用 @Value("${property}")
注释注入配置属性有时会很麻烦,尤其是当你使用多个属性或你的数据是分层的时候。
Spring Boot 引入了一个可替换的方案 —— @ConfigurationProperties 来注入属性。
JavaBean 属性绑定
@Data
@ConfigurationProperties("my.service")
public class MyProperties {
// 我们可以简单地用一个值初始化一个字段来定义一个默认值
private boolean enabled = true;
private InetAddress remoteAddress;
private final Security security = new Security();
@Data
public static class Security {
private String username;
private String password;
// 如果这个属性配置的话,默认是“USER”
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
}
}
在配置文件中进行如下配置:
my:
service:
enabled: true
remoteAddress: 127.0.0.1
security:
username: csx
password: passwoed
roles:
- role1
- role2
最后生成的 Bean 的属性如下:
{
"enabled": true,
"remoteAddress": "127.0.0.1",
"security": {
"username": "csx",
"password": "passwoed",
"roles": [
"role1",
"role2"
]
}
}
以上的绑定当时需要提供默认的构造函数,以及get/setter方法。
并且不支持 JavaBean 中的静态成员变量的数据绑定
另外,@ConfigurationProperties 还有两个其他属性。
@ConfigurationProperties( value = "my.service",
ignoreInvalidFields = false,
ignoreUnknownFields = false)
ignoreInvalidFields:是否忽略非法值,比如将一个字符串 “foo” 赋值给 bool 值,不忽略的话会报启动异常。
ignoreUnknownFields:对于多余的配置是否会报异常。
构造函数绑定
有些情况下,我们需要绑定的 JavaBean 是不可变的(防止配置注入 Bean 以后,开发者在程序中错误地将配置改掉了)。这种情况下我们可以使用构造函数形式的绑定,只提供 getter 方法。
@Getter
@ConstructorBinding
@ConfigurationProperties("my.service")
public class MyProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security;
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
@Getter
public static class Security {
private String username;
private String password;
private List<String> roles;
public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
}
}
@DefaultValue 可以指定默认值。
使用构造函数绑定的方式,只能 @EnableConfigurationProperties 或者 @ConfigurationPropertiesScan 的方式激活 Bean。而不能使用 @Component、@Bean 或者 @Import 的方式进行数据绑定。
如果你的类有多个构造函数,可以直接指定使用哪个。
@ConstructorBinding
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
激活方式
方式一:添加 @Component 注解
上面的方式需要保证 MyProperties 能被 Spring 扫到。
@Data
@Component
@ConfigurationProperties("my.service")
public class MyProperties {
}
方式二:通过 @Bean 方法
@Configuration
public class ServiceConfig {
@Bean
public MyProperties myProperties(){
return new MyProperties();
}
}
方式三:@EnableConfigurationProperties(推荐)
@Configuration
@EnableConfigurationProperties(MyProperties.class)
public class ServiceConfig {
}
方式四:@ConfigurationPropertiesScan
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {
}
引用方式
我们通过配置在 Spring 容器中生成了配置 Bean,那么需要怎么使用他们呢?
@Service
public class MyService {
// 依赖注入
@Autowired
private MyProperties properties;
public void service(){
System.out.println(properties.getRemoteAddress());
}
}
@Service
public class MyService {
private MyProperties properties;
// 通过构造函数注入,一般推荐这种方式
public MyService(MyProperties properties) {
this.properties = properties;
}
public void service(){
System.out.println(properties.getRemoteAddress());
}
}
给第三方类绑定值
假如某些类不是你自己开发的,你也想使用 @ConfigurationProperties 的方式给他绑定值,那么可以进行下面的方式进行配置。
@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {
@Bean
@ConfigurationProperties(prefix = "another")
public AnotherComponent anotherComponent() {
return new AnotherComponent();
}
}
宽松绑定原则(Relaxed Binding)
所谓的宽松绑定原则是指:并不是 JavaBean 中的属性必须要和配置文件中的一致才能绑定数据,context-path 也能绑定到 contextPath 属性上。下面举个列子:
@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
下面的几种方式,都能将配置文件或者环境变量中的值绑定到 firstName 上。
形式 | 使用场景 |
---|---|
my.main-project.person.first-name | 推荐使用在 .properties and .yml files. |
my.main-project.person.firstName | Standard camel case syntax. |
my.main-project.person.first_name | 推荐使用在 .properties and .yml files. |
MY_MAINPROJECT_PERSON_FIRSTNAME | 推荐使用在系统环境变量读取配置时使用 |
和 @Value 对比
@Value 是 Spring Framework 中的注解,而 @ConfigurationProperties 是在 Spring Boot 中引入的。
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.