SpringBoot--如何整体读取多个配置属性及其相关操作
上篇文章讲到使用@Value注解每次只能读取一个配置属性,若要整体读取多个属性,或者读取具有某种结构关系的一组属性可使用@ConfigurationProperties注解来处理。
@ConfigurationProperties注解的两种用法:
- 修饰属性处理类:当@ConfigurationProperties修饰的类被部署为容器中的Bean时,改注解指定的属性会被注入该Bean的属性。因此,@ConfigurationProperties修饰的类称为“属性处理类”。
- 修饰@Bean注解修饰的方法:使用@Bean修饰的方法蒋会配置一个容器中的Bean,而@ConfigurationProperties指定的属性会被注入该Bean的属性。
看不懂没关系,下面会有代码示例。
在使用@ConfigurationProperties时可指定如下属性:
- prefix(或value):指定要加载的属性的前缀
- ignoreInvaildFields():指定是否忽略无效属性值。比如处理类定义了某个字段的类型是Integer,但在配置文件中的值是abc,这就是无效值。
- ignoreUnknowFields():指定是否忽略未知的字段值。如果在配置文件中配置的属性比处理类需要的属性更多,那么多出来的属性就是未知属性。
使用属性处理类获取配置属性
直接来看代码示例:
\resources\application.properties文件内容:
org.crazyit.enabled=true
org.crazyit.name=Crazy Java
org.crazyit.remoteAddress=192.168.1.188
org.crazyit.item.brand=Tesla
org.crazyit.item.comments=Good, Excellent
(使用IDEA开发属性处理类时,添加spring-boot-configuration-processor依赖,IDEA会提供“代码补全”功能。
<!-- 添加该依赖后IDEA可以提供自动补全功能 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
)
SpringBoot不会自动启用@ConfigurationProperties注解,启用该注解有如下方式:
- 为@ConfigurationProperties注解修饰的类加@Component注解
- 为@ConfigurationProperties注解修饰的类显式配置成容器中的bean
- 使用@EnableConfigurationProperties注解,该注解显式指定一个或多个属性处理类,SpringBoot会启用这些属性处理类上的@ConfigurationProperties注解
- 使用@ConfigurationPropertiesScan注解,该注解指定一个或多个包及其子包下所有带@ConfigurationProperties注解的类
@ConfigurationProperties注解修饰的属性处理类代码:
// 指定读取以org.crazyit.*开头的属性
@ConfigurationProperties(prefix = "org.crazyit", ignoreUnknownFields=false)
@Component
public class CrazyitProperties
{
// 指定同名的实例变量和setter方法。SpringBoot会通过反射调用setter方法来完成属性值注入
private boolean enabled;
private String name;
private InetAddress remoteAddress;
private final Item item = new Item();
// 省略getter\setter
public static class Item
{
private String brand;
private List<String> comments = new ArrayList<>(Collections.singleton("GREAT"));
// 省略getter\setter
}
}
控制器类代码示例:
@RestController
public class HelloController
{
private final CrazyitProperties crazyitProperties;
// 依赖注入CrazyitProperties属性处理Bean
@Autowired
public HelloController(CrazyitProperties crazyitProperties)
{
this.crazyitProperties = crazyitProperties;
}
@GetMapping
public CrazyitProperties hello()
{
return crazyitProperties;
}
}
运行结果:

属性处理类也支持使用构造器完成属性值注入,但是要额外使用@ConstructorBinding修饰用于执行构造注入的构造器。注意:使用构造器注入,必须使用@EnableConfigurationProperties或者@ConfigurationPropertiesScan注解来启用@ConfigurationProperties注解。
属性处理类示例:
@ConfigurationProperties(prefix = "org.crazyit", ignoreUnknownFields=false)
public class CrazyitProperties
{
private boolean enabled;
private String name;
private InetAddress remoteAddress;
private final Item item;
@ConstructorBinding
public CrazyitProperties(boolean enabled, String name, InetAddress remoteAddress, Item item)
{
this.enabled = enabled;
this.name = name;
this.remoteAddress = remoteAddress;
this.item = item;
}
// 省略getter\setter
public static class Item
{
private String brand;
private List<String> comments = new ArrayList<>(Collections.singleton("GREAT"));
// 省略getter\setter
}
}
application.yml
org:
crazyit:
enabled: true
name: 哈利波特
remote-address: 192.168.1.188
item:
brand: Apple
comments:
- Good
- Excellent
上面配置的属性为org.crazyit.remote-address与CrazyitProperties类中定义的remoteAddress属性不完全相同,SpringBoot能成功注入吗?
答案是肯定的,因为SpringBoot支持宽松绑定(Relaxed Binding)。它不要求配置的属性名和属性处理类中的属性名完全相同。
宽松绑定的四种情况(这4种情况都能完成注入):
- org.crazyit.remote-address
- org.crazyit. remoteAddress
- org.crazyit. remote_address
- ORG_CRAZYIT_REMOTEADDRESS
在*.properties和 *.yml文件中配置List类型的属性有较小的区别:
- 在*.properties文件中配置List有2种方式:英文逗号隔开多个值;用标准方括号
- 在 *.yml文件中配置List有2种方式:英文逗号隔开多个值;用短横线开头(例子所示)
因此,*.properties和 *.yml文件中,都可以用英文逗号隔开多个值来构建List。
App.java示例
@SpringBootApplication
// 指定扫描org.crazyit.app.config包及其子包下的@ConfigurationProperties注解修饰的类
@ConfigurationPropertiesScan("org.crazyit.app.config")
public class App
{
public static void main(String[] args)
{
// 创建Spring容器、运行Spring Boot应用
SpringApplication.run(App.class, args);
}
}
为容器中的bean注入配置属性
@ConfigurationProperties注解除了可修饰类,还可修饰@Bean注解修饰的方法。
代码示例:Book类
public class Book
{
private String title;
private double price;
private String author;
private List<String> keywords;
// 省略getter、setter
}
代码示例:配置类
@Configuration
public class MyConfig
{
@Bean
// @ConfigurationProperties注解会驱动Spring自动调用该Bean的setter方法
@ConfigurationProperties("fkjava.book")
public Book book()
{
return new Book();
}
}
代码示例:application.yml
fkjava:
book:
title: "美语音标"
price: 128
author: "赖世雄"
keywords:
- 英语
- 音标
代码示例:控制器类
@RestController
public class HelloController
{
private final Book book;
// 通过构造器注入Book对象
@Autowired
public HelloController(Book book)
{
this.book = book;
}
@GetMapping
public Book hello()
{
return book;
}
}
运行结果:

@Value和 @ConfigurationProperties的对比
| 特征 | @ConfigurationProperties | @Value |
|---|---|---|
| 注入的属性个数 | 批量 | 单个 |
| 宽松绑定 | 支持 | 部分支持 |
| SpEL | 不支持 | 支持 |
| 元数据支持 | 支持 | 不支持 |
属性转换
SpringBoot内置了常用的类型转换机制,如果在转换失败,则应用启动会失败,并抛出异常。如果要忽略转换失败的属性,可将@ConfigurationProperties注解的ignoreInvaildFields属性设为true(默认是false)。
SpringBoot可自动转换如下类型:Duration、Period、DataSize,并支持为属性值指定单位。
- Duration类型可指定的单位:ns纳秒、μs微妙、ms毫秒、s秒、m分钟、h小时、d天。
- Period类型可指定的单位:y年、m月、w星期、d天。(例如配置1y3d,代表1年3天)。
- DataSize类型可指定的单位:B字节、KB千字节、MB兆字节、GB吉字节、TB太字节
代码示例:属性处理类
// 指定读取以org.crazyit.*开头的属性
@ConfigurationProperties(prefix = "org.crazyit")
@Component
public class CrazyitProperties
{
private Duration timeout;
// @DurationUnit注解指定默认的时间单位
@DurationUnit(ChronoUnit.SECONDS)
private Duration lastTime;
private Period runPeriod;
// @DataSizeUnit注解指定默认的数据单位
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize maxSize;
// 省略getter、setter
}
代码示例:application.properties
org.crazyit.timeout=30000
# 默认单位是秒
org.crazyit.last-time=45
org.crazyit.run-period=2m5d
org.crazyit.max-size=2
代码示例:控制器类
@RestController
public class HelloController
{
private final CrazyitProperties crazyitProperties;
// 依赖注入CrazyitProperties属性处理Bean
@Autowired
public HelloController(CrazyitProperties crazyitProperties)
{
this.crazyitProperties = crazyitProperties;
}
@GetMapping
public Map<String, Object> hello()
{
System.out.println(crazyitProperties.getMaxSize().toKilobytes());
return Map.of("props", crazyitProperties,
"maxSize", crazyitProperties.getMaxSize().toKilobytes());
}
}
运行结果:

校验@ConfigurationProperties
只要为属性处理类添加@Validated注解,并使用JSR303的校验注解修饰需要校验的示例变量,SpringBoot会自动校验配置文件中的属性值。如果某个属性校验不通过,应用会启动失败,并用FailureAnalyzer显式校验错误。
如果属性处理类包含复合类型的属性,且要对复合类型的子属性进行校验,则应为该复合类型的属性添加@Valid注解。
@ConfigurationProperties校验基于JSR303,因此必须添加JSR303依赖,spring-boot-starter-validation依赖库包含了JSR303的依赖,因此要在pom文件中添加以下依赖
<!-- 添加Spring Boot Validation依赖库 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
属性处理类示例:
// 指定读取以org.crazyit.*开头的属性
@ConfigurationProperties(prefix = "org.crazyit", ignoreUnknownFields=false)
@Component
@Validated
public class CrazyitProperties
{
@NotEmpty
private String name;
@Range(max = 150, min=90, message = "价格必须位于90~150之间")
private double price;
@Pattern(regexp = "[1][3-8][0-9]{9}", message = "必须输入有效的手机号")
private String mobile;
@Valid
private final Item item = new Item();
// 省略getter setter
public static class Item
{
@Length(min=5, max=10, message = "品牌名长度必须在5到10个字符")
private String brand;
@Size(min = 1, message = "comments至少包含一个元素")
private List<String> comments = new ArrayList<>(Collections.singleton("GREAT"));
// 省略getter、setter
}
}
代码示例:application.properties
org.crazyit.name=Crazy Java
org.crazyit.price=89
org.crazyit.mobile=13334444
org.crazyit.item.brand=Apple
org.crazyit.item.comments=Great, Excellent
运行结果:

对于使用@ConfigurationProperties修饰@Bean方法的情况,同样可对配置属性进行校验,主要为@Bean方法添加@Validated注解即可。
SpringBoot--如何整体读取多个配置属性及其相关操作的更多相关文章
- SpringBoot入门篇--读取资源文件配置
在项目的开发中,我们知道的是SpringBoot框架大大减少了我们的配置文件,但是还是留下了一个application.properties文件让我们可以进行一些配置.当然这些配置必然是包括服务器的配 ...
- 理解中WebAPI的属性和相关操作 FormBody和 FormUri等(WebAPI 二)
1.FromUri使用 将数据通过url方式传递.我们需要在webapi方法标明,这个参数只接受url中参数的值, $("#Save").click(function () { $ ...
- 外部配置属性值是如何被绑定到XxxProperties类属性上的?--SpringBoot源码(五)
注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 SpringBoot是如何实现自动配置的?--SpringBoot源码(四) 温故而知新,我们来简单回顾一下上 ...
- springboot 入门二- 读取配置信息一
在上篇入门中简单介绍下springboot启动使用了大量的默认配置,在实际开发过程中,经常需要启动多个服务,那端口如何手动修改呢? 此篇就是简单介绍相关的配置文件信息. Spring Boot允许外部 ...
- SpringBoot @Value读取properties文件的属性
SpringBoot在application.properties文件中,可以自定义属性. 在properties文件中如下示: #自定义属性 mail.fromMail.addr=lgr@163.c ...
- SpringBoot配置属性之Migration
SpringBoot配置属性系列 SpringBoot配置属性之MVC SpringBoot配置属性之Server SpringBoot配置属性之DataSource SpringBoot配置属性之N ...
- springboot快速入门(二)——项目属性配置(日志详解)
一.概述 application.properties就是springboot的属性配置文件 在使用spring boot过程中,可以发现项目中只需要极少的配置就能完成相应的功能,这归功于spring ...
- SpringBoot配置属性之Server
SpringBoot配置属性系列 SpringBoot配置属性之MVC SpringBoot配置属性之Server SpringBoot配置属性之DataSource SpringBoot配置属性之N ...
- SpringBoot配置属性转载地址
SpringBoot配置属性系列 SpringBoot配置属性之MVC SpringBoot配置属性之Server SpringBoot配置属性之DataSource SpringBoot配置属性之N ...
- SpringBoot配置属性之其他
SpringBoot配置属性系列 SpringBoot配置属性之MVC SpringBoot配置属性之Server SpringBoot配置属性之DataSource SpringBoot配置属性之N ...
随机推荐
- mac使用pptp的正确方式
环境:macos mojave 10.14.6 尝试的解决方案: mac自带vpn 结论:已经不支持pptp协议 使用shimo 结论:无用,连接的时候没反应 为了解决不能连接的问题,某老外写的ppt ...
- Windows查看端口占用、相应进程、杀死进程等[netstat]
Windows 通过cmd或powerShell查看端口占用.相应进程.杀死进程等的命令 由于一般开发环境是在windows上,相应的一些测试必然涉及到一些端口的监听与使用.当开发使用的端口被占用后, ...
- redis 中文乱码
查询数据时中文乱码 解决方法: 使用 ./redis-cli 登录的时候加上 --raw参数 ./redis-cli --raw
- HarmonyOS运动开发:如何集成百度地图SDK、运动跟随与运动公里数记录
前言 在开发运动类应用时,集成地图功能以及实时记录运动轨迹和公里数是核心需求之一.本文将详细介绍如何在 HarmonyOS 应用中集成百度地图 SDK,实现运动跟随以及运动公里数的记录. 一.集成百度 ...
- Linux系列:聊一聊 SystemV 下的进程间共享内存
一:背景 1. 讲故事 昨天在分析一个 linux 的 dump 时,看到了这么一话警告,参考如下: 0:000> !eeheap -gc *** WARNING: Unable to veri ...
- vue3 基础-data-methods-computed-watch
本篇来简单了解 vue 的数据, 方法, 计算属性和监听器等相关内容. data ( ) vue 里面的 data ( ) 函数返回一些能供模板 template 直接使用的数据, 以变量的方式进行 ...
- 字典(Dictionary) update()方法
描述 python字典(Dictionary) update()函数吧dict2的键/值对更新到dict里 语法 dict.update(dict2) 参数 dict2 -- 添加到指定字典dict里 ...
- Golang相关环境变量
GOROOT: GO语言的安装路径,linux系统下一般是/usr/local/go GOPATH: 程序员自己的go源码路径,比如开发一个Helloworld的项目,那么它的代码文件夹就应该放在GO ...
- 搭建邮局-3.安装邮局前端roundcube和测试
目录 搭建邮局-1.安装hMailserver和配置邮局 https://www.cnblogs.com/daen/p/16040202.html 搭建邮局-2.添加域名和域名解析 https://w ...
- k8s | 重启Kubernetes Pod的几种方式
前言 在使用 docker 的过程中,我们可以使用docker restart {container_id}来重启容器,但是在 kubernetes 中并没有重启命令(没有 kubectl resta ...