在 SpringBoot
项目中,我们经常在配置文件application.properties
或 application.yml
中存放配置参数。
本文就对SpringBoot
对@Value
和@ConfigurationProperties
注解的区别和用法进行介绍
参考: SpringBoot | @Value 和 @ConfigurationProperties 的区别
对比内容 | @ConfigurationProperties | @Value |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
松散语法的意思就是一个属性在配置文件中可以有多个属性名,举个栗子:实体类当中的firstName
属性,在配置文件中可以是firstName
、first-name
、first_name
以及FIRST_NAME
。
@ConfigurationProperties
是支持这种命名的,而@Value
是不支持的。以firstName
为例的测试代码见参考文档。
SpEL
使用#{…}
作为定界符, 所有在大括号中的字符都将被认为是SpEL
,SpEL
为bean
的属性进行动态赋值提供了便利。
复杂类型封装指的是,在对象以及Map
(如实体中的名字类以及Map
)等属性中,用@Value
取是取不到值,示例见参考文档。
spring-boot.version: 2.3.2.RELEASE
dog:
age: 12
hobbies: #[吃喝睡, 打豆豆]
- 吃喝睡
- 打豆豆
scores: #{eq: 90, iq: 85}
eq: 90
iq: 85
groups: #{one: {num: 2}, two: {len: 4, ok-go: 6}}
one: {num: 2}
two: {len: 4, ok-go: 6}
name: #{first-name: lao, last-name: liu}
first-name: lao
last-name: liu
names: #[{first-name: su, last-name: si},{first-name: se, last-name: xi}]
- {first-name: su, last-name: si}
- {first-name: se, last-name: xi}
friends: #{lila: {first-name: li, last-name: la},xihu: {first-name: xi, last-name: hu}}
lila: {first-name: li, last-name: la}
xihu: {first-name: xi, last-name: hu}
@Data
@Configuration
@ConfigurationProperties(prefix = "dog")
public class DogConfigProperties {
private Integer age;
private List<String> hobbies;
private Map<String, Integer> scores;
private Map<String, Map<String, Integer>> groups;
private Name name;
private List<Name> names;
private Map<String, Name> friends;
@Data
public static class Name {
private String firstName;
private String lastName;
}
}
输出结果
DogConfigProperties(age=12, hobbies=[吃喝睡, 打豆豆], scores={iq2=84, eq=90, iq=85}, groups={two={ok-go=6, len=4}, one={num=2}}, name=DogConfigProperties.Name(firstName=lao, lastName=liu), names=[DogConfigProperties.Name(firstName=su, lastName=si), DogConfigProperties.Name(firstName=se, lastName=xi)], friends={lila=DogConfigProperties.Name(firstName=li, lastName=la), xihu=DogConfigProperties.Name(firstName=xi, lastName=hu)})
复杂封装类型如list,map等推荐使用@ConfigurationProperties
@ConfigurationProperties示例源码
@ConfigurationProperties
的几种方式有以下几种方法:
@ConfigurationPropertiesScan
@EnableConfigurationProperties(value = [DogConfigProperties::class])
DogConfigProperties
类上添加@Component
注解进行实例化(本质上与2无区别)@Configuration
注解的类内手动创建 @Bean
@Configuration
@EnableConfigurationProperties( DogConfigProperties.class )
public class DogConfig {
@Autowired
private DogConfigProperties dogConfigProperties;
@Bean
public Map dogData() {
Map map = new HashMap();
map.put("first name", dogConfigProperties.getName().getFirstName() );
map.put("age", dogConfigProperties.getAge() );
// ...
return map;
}
}
@Value
支持三种取值方式,分别是 字面量,${key}从环境变量、配置文件中获取值,#{SpEL}
java.lang.IllegalArgumentException: Could not resolve placeholder 'man.xxx' in value "${man.xxx}"
:
即可SpEL
才能解析,语法:#{…}
,否则报错:java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map': no matching editors or conversion strategy found
man.nick: tim
@Value("${man.nick:}")
private String nick;
output: tim
未配置时,nick=“”
man.victors: 44,55,66
@Value("${man.victors:}")
private List<Integer> victors;
output: [44,55,66]
未配置时,victors=[]
低版本需使用EL
表达式进行解析:
#{'${man.victors:44,55}'.split(',')}
==> output: [44,55]#{'${man.victors:}'.empty ? new String[0] : '${man.victors:}'.split(',')}
==> output: null
man.scores: {'eq': 99, 'iq': 88}
@Value("#{${man.scores:{'eq': 90, 'iq': 85}}}")
private Map<String, Integer> scores;
output: {eq=99, iq=88}
默认值
#{${man.scores:{}}}
==> output: null
EL
表达式
@Value示例源码