使用@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 |