【根底系列】ConfigurationProperties 配置绑定中那些你不晓得的事件
在 SpringBoot 我的项目中,获取配置属性能够说是一个非常简单的事件,将配置写在 aplication.yml
文件之后,咱们就能够间接通过 @Value
注解来绑定并获取;此外咱们也能够将一个结构化的配置,借助 @ConfigurationPorperties
绑定到一个 POJO,而后供我的项目应用,那么在应用它的时候,不知是否有想过
@ConfigurationPorperties
润饰的类如何失效- 配置参数与定义的 POJO 类型不匹配时会怎么
- 配置参数的必要性校验能够怎么反对
- 自定义的配置参数,idea 中如何主动补全
- 已废除的参数定义,怎么敌对的提醒应用方
- List/Map 格局的参数,怎么应用
- 自定义参数解析规定如何反对
如果下面这些都曾经了然于心,那么本文的帮忙将不会特地大;如果对此有所疑难,接下来将逐个进行解惑
<!– more –>
I. 我的项目环境
本我的项目借助 SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
进行开发
上面是外围的pom.xml
(源码能够再文末获取)
<!-- 这个依赖是干嘛的,后文会介绍 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
II. ConfigurationProperties 详解
1. 配置绑定
假设咱们当初自定义一个功能模块,外面有一些咱们自定义的参数,反对通过 yaml 配置文件的形式注入
首先咱们能够先定义一个配置类 BindConfig
@Data
@ConfigurationProperties(prefix = "hhui.bind")
public class BindConfig {
private String name;
private Integer age;
private List<String> list;
private Map<String, String> map;
}
请留神下面的注解中,prefix = hhui.bind
,简略来讲就是会读取配置文件中,前缀为 hhui.bind
的属性,而后顺次赋值到这个类中
BindConfig.name = hhui.bind.name
BindConfig.age = hhui.bind.age
- …
对应的配置文件如下
hhui:
bind:
name: YiHui
age: 18
list:
- java
- c
- python
map:
wechat: 小灰灰 blog
blogs: http://blog.hhui.top
git: http://github.com/liuyueyi
注意事项
- 配置类必须有公共的 Setter 办法,上文中次要是借助 lombok 的
@Data
省略了 Setter 办法的显示申明而已 -
类的属性名与配置文件中的配置名要求匹配
- 大小写不敏感
- 反对下划线转驼峰
- 配置类不要求必须是 public
对于下面最初一点,也就表明咱们能够在主动 AutoConfiguration 类中,申明一个外部类来绑定配置信息,如下
@Configuration
@EnableConfigurationProperties({AutoConfiguration.BindConfig.class})
public class AutoConfiguration {
@Data
@ConfigurationProperties(prefix = "hhui.bind")
static class BindConfig {
private String name;
private Integer age;
private List<String> list;
private Map<String, String> map;
}
}
2. 注册失效
咱们通过 @ConfigurationProperties
润饰配置类之后,是否间接会失效呢?通常来讲,让它失效有上面三种形式
a. @Component
等注解润饰形式
间接在配置类上增加 @Component
, @Configuration
等注解,让 Spring 容器扫描并加载它
@Data
@Component
@ConfigurationProperties(prefix = "hhui.bind")
public class BindConfig {}
应用这种形式时,须要留神配置类在主动扫描的包门路下,否则可能不会被扫描(次要是作为第三方 jar 包提供服务时,可能呈现扫描不到的问题)
b. @Bean
注册
把它当成一个一般的 bean,借助 bean 注册的形式来实现,也是一个可选的计划,个别的实现形式如下
@Configuration
public class AutoConfiguration {
@Bean
public BindConfig bindConfig() {return new BindConfig();
}
}
c. @EnableConfigurationProperties
形式
在配置类上,增加这个注解之后,能够实现配置注册,个别常见的应用姿态如
@EnableConfigurationProperties({BindConfig.class})
@Configuration
public class AutoConfiguration {}
d. 小结
下面三种注册形式,后面两种的思路是将配置类作为 bean,第三种实现思路和被动注册 bean 统一(所以想实现被动注册 bean,能够思考它的实现逻辑)
3. 参数类型不匹配
如果咱们在配置中,一个原本心愿接管 int 类型的参数,后果实际上填了一个非整形,会怎么?
比方后面的配置类,咱们理论的配置文件将 age
填 18y,来看一下最终会产生什么事件
hhui:
bind:
Name: YiHui
AGE: 18y
list:
- java
- c
- python
map:
wechat: 小灰灰 blog
blogs: http://blog.hhui.top
git: http://github.com/liuyueyi
简略演示,间接在启动类中测试一下会如何
@SpringBootApplication
public class Application {public Application(BindConfig config) {System.out.println(config);
}
public static void main(String[] args) {SpringApplication.run(Application.class);
}
}
参数异样之后,间接启动失败,如果对参数的要求没有那么严格,即容许失败,咱们能够通过设置ignoreInvalidFields = true
@Data
@ConfigurationProperties(prefix = "hhui.bind", ignoreInvalidFields = true)
public class BindConfig {}
再次执行之后,会发现失常启动,输入如下
BindConfig(name=YiHui, age=null, list=[java, c, python], map={wechat= 小灰灰 blog, blogs=http://blog.hhui.top, git=http://github.com/liuyueyi})
留神查看下面的 age,因为传入的参数非法,所以是 null
阐明
联合默认值 + ignoreInvalidFields
形式来反对配置的最大可用性:
- 间接在配置类中,设置属性的默认值,示意当这个配置不存在或者设置非法时,应用默认的配置
@Data
@ConfigurationProperties(prefix = "hhui.bind", ignoreInvalidFields = true)
public class BindConfig {
private String name;
private Integer age = 18;
private List<String> list;
private Map<String, String> map;
}
再次执行输入如
BindConfig(name=YiHui, age=18, list=[java, c, python], map={wechat= 小灰灰 blog, blogs=http://blog.hhui.top, git=http://github.com/liuyueyi}, mainPwd=Pwd(user= 一灰灰 blog, pwd=yihuihui, code=9))
4. 配置解析规定
常见的配置除了根本类型之外,能嵌套自定义对象么,非根本类型又能够如何解析呢?
a. POJO,List,Map 参数类型
咱们新定义一个 Pwd 类
@Data
public class Pwd {
private String user;
private String pwd;
private Integer code;
}
而后扩大一下BindConfig
@Data
@ConfigurationProperties(prefix = "hhui.bind", ignoreInvalidFields = true)
public class BindConfig {
private String name;
private Integer age = 18;
private List<String> list;
private Map<String, String> map;
private Pwd mainPwd;
}
这个时候 mainPwd 对应的 yaml 配置文件能够如下设置
hhui:
bind:
Name: YiHui
AGE: 1h
list:
- java
- c
- python
map:
wechat: 小灰灰 blog
blogs: http://blog.hhui.top
git: http://github.com/liuyueyi
# 上面这个对应的是 BindConfg.mainPwd; 能够写成 main_pwd 也能够写成 mainPwd
main_pwd:
user: 一灰灰 blog
pwd: yihuihui
code: 9
从下面的介绍也能够看出,对于自定义的 POJO 类是反对的,应用姿态也没什么区别
此外,对于 List 和 Map 的应用也给出了实例
b. 自定义配置解析
下面咱们自定义的 Pwd
类,次要借助 setter
办法,将匹配的属性塞入进去;如果我的配置就是一个 json 串,能够注入到一个 POJO 类么
hhui:
bind:
Jwt: '{"token":"11111111123","timestamp": 1610880489123}'
对应的 Jwt 类如下
@Data
public class Jwt {
private String token;
private Long timestamp;
}
这个时候如想实现下面的配置解析,能够通过实现 org.springframework.core.convert.converter.Converter
接口来反对,并通过 @ConfigurationPropertiesBinding
注解来表明这是个配置属性转换类,不加这个注解会不失效哦
@Component
@ConfigurationPropertiesBinding
public class JwtConverter implements Converter<String, Jwt> {
@Override
public Jwt convert(String source) {return JSONObject.parseObject(source, Jwt.class);
}
}
阐明
应用自定义的配置解析规定时,留神两点
- 实现接口
Converter
- 应用
@ConfigurationPropertiesBinding
润饰注解
Spring 提供了一些默认的配置解析规定,如
-
文件大小
DataSize
- 对应的 value 能够是 1B, 1KB, 1MB, 1GB…
-
持续时间
Duration
- 对应的 value 可已是 1ns,1us,1ms,1s,1m,1h,1d
5. 配置不存在场景
一个配置类,对应的类中没有这个属性会怎么?
如针对后面的 BindConfig
,没有notExist
这个属性,然而配置文件中,却加上了这个
hhui:
bind:
notExist: true
实测之后,发现没有任何影响,通过查看 @ConfigurationProperties
注解的成员,发现能够设置ignoreUnknownFields=false
,从字面上示意呈现了未能辨认的成员,不会略谬误,然而在理论测试中,并没有失效
6. 参数校验
参数校验能够说比拟罕用的 case 了,比方后面的配置 age
,基本上不会容许这个参数能是正数,如须要对参数进行校验,咱们能够借助@Validated
来实现校验
增加 pom 依赖
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
而后再配置类上增加@Validated
,而后就能够在须要校验的字段上增加对应的限度
@Data
@Validated
@ConfigurationProperties(prefix = "hhui.bind", ignoreInvalidFields = true, ignoreUnknownFields = false)
public class BindConfig {@Min(13)
@Max(66)
private Integer age = 18;
}
如果咱们将 age 参数设置不满足下面的条件
hhui:
bind:
age: 10
再次测试会发现报如下谬误
7. IDEA 主动补全提醒
平时在 Spring 开发过程中,在 yaml 文件中增加配置时,配合 idea 有十分敌对的提醒,能够十分敌对的补全参数配置
那么咱们自定义的参数想实现这个成果应该怎么做呢?
增加文章最结尾的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
增加下面的依赖之后,打包mvn clean package
,而后会发现在 META-INF 上面有个spring-configuration-metadata.json
{
"groups": [
{
"name": "hhui.bind",
"type": "com.git.hui.boot.bind.config.BindConfig",
"sourceType": "com.git.hui.boot.bind.config.BindConfig"
}
],
"properties": [
{
"name": "hhui.bind.age",
"type": "java.lang.Integer",
"sourceType": "com.git.hui.boot.bind.config.BindConfig",
"defaultValue": 18
},
{
"name": "hhui.bind.jwt",
"type": "com.git.hui.boot.bind.config.Jwt",
"sourceType": "com.git.hui.boot.bind.config.BindConfig"
},
{
"name": "hhui.bind.list",
"type": "java.util.List<java.lang.String>",
"sourceType": "com.git.hui.boot.bind.config.BindConfig"
},
{
"name": "hhui.bind.main-pwd",
"type": "com.git.hui.boot.bind.config.Pwd",
"sourceType": "com.git.hui.boot.bind.config.BindConfig"
},
{
"name": "hhui.bind.map",
"type": "java.util.Map<java.lang.String,java.lang.String>",
"sourceType": "com.git.hui.boot.bind.config.BindConfig"
},
{
"name": "hhui.bind.name",
"type": "java.lang.String",
"sourceType": "com.git.hui.boot.bind.config.BindConfig"
}
],
"hints": []}
而后主动补全就有了
阐明
idea 举荐增加插件Spring Assistant
,反对十分敌对的配置注入
8. 小结
本文介绍了 @ConfigurationProperties
润饰 POJO 类,实现配置的绑定,能够通过将这个类申明为一个一般 bean 的形式进行注册,也能够借助 @EnableConfigurationProperties
来注册
在配置参数时,须要留神如果参数类型不统一,会导致我的项目启动失败;能够通过设置ConfigurationProperties#ignoreInvalidFields = true
,来防止这种场景
通过实现接口 Converter
+ @ConfigurationPropertiesBinding
来自定义参数解析转换规则,能够实现各路姿态的参数解析
配置的主动提醒反对也比较简单,增加 org.springframework.boot:spring-boot-configuration-processor
依赖,打包之后在 META-INF 中会多一个 json 文件spring-configuration-metadata.json
II. 其余
0. 我的项目
我的项目源码
- 工程:https://github.com/liuyueyi/spring-boot-demo
- 源码: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/002-properties-bind
系列博文
- 【根底系列】实现一个自定义配置加载器(利用篇)
- 【根底系列】SpringBoot 配置信息之默认配置
- 【根底系列】SpringBoot 配置信息之配置刷新
- 【根底系列】SpringBoot 根底篇配置信息之自定义配置指定与配置内援用
- 【根底系列】SpringBoot 根底篇配置信息之多环境配置信息
- 【根底系列】SpringBoot 根底篇配置信息之如何读取配置信息
1. 一灰灰 Blog
尽信书则不如,以上内容,纯属一家之言,因集体能力无限,不免有疏漏和谬误之处,如发现 bug 或者有更好的倡议,欢送批评指正,不吝感谢
上面一灰灰的集体博客,记录所有学习和工作中的博文,欢送大家前去逛逛
- 一灰灰 Blog 集体博客 https://blog.hhui.top
- 一灰灰 Blog-Spring 专题博客 http://spring.hhui.top
- 微信公众号: 一灰灰 blog