一、配置文件分类
在进行SpringBoot相关的配置时默认使用properties格式,但是properties格式的配置写起来总是觉得看着不舒服,所以就期望存在一种书写起来更简便的配置格式提供给开发者使用。有吗?还真有,SpringBoot除了支持properties格式的配置文件,还支持另外两种格式的配置文件。三种配置文件格式分别如下:
application.properties(properties格式) server.port=80 application.yml(yml格式) server: port: 81 application.yaml(yaml格式) server: port: 82
对于这三种格式来说,以后用哪一种比较多呢?记清楚,以后基本上都是用yml格式的,专栏后面的所有知识都是基于yml格式来制作的,以后在企业开发过程中用这个格式的机会也最多,一定要重点掌握。
配置文件优先级
可以简单的认为
application.properties > application.yml > application.yaml
但是我们实际开发的时候还是要看最终的效果为准。也就是你要的最终效果是什么自己是明确的,上述结论只能帮助你分析结论产生的原因。这个知识了解一下就行了,因为以后同时写多种配置文件格式的情况实在是较少。
二、yaml文件语法格式
YAML(YAML Ain’t Markup Language),一种数据序列化格式。具有容易阅读、容易与脚本语言交互、以数据为核心,重数据轻格式的特点。常见的文件扩展名有两种:
.yml格式(主流)
.yaml格式
具体的语法格式要求如下:
1,大小写敏感 2,属性层级关系使用多行描述,每行结尾使用冒号结束 3,使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键) 4,属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔) 5,#号 表示注释
上述规则不要死记硬背,按照书写习惯慢慢适应,并且在Idea下由于具有提示功能,慢慢适应着写格式就行了。核心的一条规则要记住,数据前面要加空格与冒号隔开。
下面列出常见的数据书写格式,熟悉一下
boolean: TRUE #TRUE,true,True,FALSE,false,False均可 float: 3.14 #6.8523015e+5 #支持科学计数法 int: 123 #0b1010_0111_0100_1010_1110 #支持二进制、八进制、十六进制 null: ~ #使用~表示null string: HelloWorld #字符串可以直接书写 string2: "Hello World" #可以使用双引号包裹特殊字符 date: 2018-02-17 #日期必须使用yyyy-MM-dd格式 datetime: 2018-02-17T15:02:31+08:00 #时间和日期之间使用T连接,最后使用+代表时区
此外,yaml格式中也可以表示数组,在属性名书写位置的下方使用减号作为数据开始符号,每行书写一个数据,减号与数据间空格分隔。
subject: - Java - 前端 - 大数据 enterprise: name: itcast age: 16 subject: - Java - 前端 - 大数据 likes: [王者荣耀,刺激战场] #数组书写缩略格式 users: #对象数组格式一 - name: Tom age: 4 - name: Jerry age: 5 users: #对象数组格式二 - name: Tom age: 4 - name: Jerry age: 5 users2: [ { name:Tom , age:4 } , { name:Jerry , age:5 } ] #对象数组缩略格式
三、yaml数据读取
对于yaml文件中的数据,其实你就可以想象成这就是一个小型的数据库,里面保存有若干数据,每个数据都有一个独立的名字,如果你想读取里面的数据,肯定是支持的,下面就介绍3种读取数据的方式。
1,单一数据读取
yaml中保存的单个数据,可以使用Spring中的注解@Value读取单个数据,属性名引用方式:${一级属性名.二级属性名……}
记得使用@Value注解时,要将该注解写在某一个指定的Spring管控的bean的属性名上方,这样当bean进行初始化时候就可以读取到对应的单一数据了。
2,读取全部数据
读取单一数据可以解决读取数据的问题,但是如果定义的数据量过大,这么一个一个书写肯定会累死人的,SpringBoot提供了一个对象,能够把所有的数据都封装到这一个对象中,这个对象叫做Environment,使用自动装配注解可以将所有的yaml数据封装到这个对象中
数据封装到了Environment对象中,获取属性时,通过Environment的接口操作进行,具体方法是getProperties(String),参数填写属性名即可
3,读取对象数据
单一数据读取书写比较繁琐,全数据读取封装的太厉害了,每次拿数据还要一个一个的getProperties(),总之用起来都不是很舒服。由于Java是一个面向对象的语言,很多情况下,我们会将一组数据封装成一个对象。SpringBoot也提供了可以将一组yaml对象数据封装一个Java对象的操作
首先定义一个对象,并将该对象纳入Spring管控的范围,也就是定义成一个bean,然后使用注解@ConfigurationProperties指定该对象加载哪一组yaml中配置的信息。
这个@ConfigurationProperties必须告诉他加载的数据前缀是什么,这样指定前缀下的所有属性就封装到这个对象中。记得数据属性名要与对象的变量名一一对应啊,不然没法封装。其实以后如果你要定义一组数据自己使用,就可以先写一个对象,然后定义好属性,下面到配置中根据这个格式书写即可。
四、yml配置高级
1,@ConfigurationProperties
刚才我们了解了@ConfigurationProperties注解,此注解的作用是用来为bean绑定属性的。开发者可以在yml配置文件中以对象的格式添加若干属性。
但是目前我们学的都是给自定义的bean使用这种形式加载属性值,如果是第三方的bean呢?能不能用这种形式加载属性值呢?为什么会提出这个疑问?原因就在于当前@ConfigurationProperties注解是写在类定义的上方,而第三方开发的bean源代码不是你自己书写的,你也不可能到源代码中去添加@ConfigurationProperties注解,这种问题该怎么解决呢?下面就来说说这个问题。
使用@ConfigurationProperties注解其实可以为第三方bean加载属性,格式特殊一点而已。
步骤①:使用@Bean注解定义第三方bean
@Bean public DruidDataSource datasource(){ DruidDataSource ds = new DruidDataSource(); return ds; }
步骤②:在yml中定义要绑定的属性,注意datasource此时全小写
datasource: driverClassName: com.mysql.jdbc.Driver
步骤③:使用@ConfigurationProperties注解为第三方bean进行属性绑定,注意前缀是全小写的datasource
@Bean @ConfigurationProperties(prefix = "datasource") public DruidDataSource datasource(){ DruidDataSource ds = new DruidDataSource(); return ds; }
操作方式完全一样,只不过@ConfigurationProperties注解不仅能添加到类上,还可以添加到方法上,添加到类上是为spring容器管理的当前类的对象绑定属性,添加到方法上是为spring容器管理的当前方法的返回值对象绑定属性,其实本质上都一样。
2,@EnableConfigurationProperties
做到这其实就出现了一个新的问题,目前我们定义bean不是通过类注解定义就是通过@Bean定义,使用@ConfigurationProperties注解可以为bean进行属性绑定,那在一个业务系统中,哪些bean通过注解@ConfigurationProperties去绑定属性了呢?因为这个注解不仅可以写在类上,还可以写在方法上,所以找起来就比较麻烦了。为了解决这个问题,spring给我们提供了一个全新的注解,专门标注使用@ConfigurationProperties注解绑定属性的bean是哪些。这个注解叫做@EnableConfigurationProperties。具体如何使用呢?
步骤①:在配置类上开启@EnableConfigurationProperties注解,并标注要使用@ConfigurationProperties注解绑定属性的类
@SpringBootApplication @EnableConfigurationProperties(ServerConfig.class) public class Springboot13ConfigurationApplication { }
步骤②:在对应的类上直接使用@ConfigurationProperties进行属性绑定
@Data @ConfigurationProperties(prefix = "servers") public class ServerConfig { private String ipAddress; private int port; private long timeout; }
有人感觉这没区别啊?注意观察,现在绑定属性的ServerConfig类并没有声明@Component注解。当使用@EnableConfigurationProperties注解时,spring会默认将其标注的类定义为bean,因此无需再次声明@Component注解了。
五、宽松绑定/松散绑定
什么是宽松绑定?实际上是springboot进行编程时人性化设计的一种体现,即配置文件中的命名格式与变量名的命名格式可以进行格式上的最大化兼容。兼容到什么程度呢?几乎主流的命名格式都支持,例如:
在ServerConfig中的ipAddress属性名
@Component @Data @ConfigurationProperties(prefix = "servers") public class ServerConfig { private String ipAddress; }
可以与下面的配置属性名规则全兼容
servers: ipAddress: 192.168.0.2 # 驼峰模式 ip_address: 192.168.0.2 # 下划线模式 ip-address: 192.168.0.2 # 烤肉串模式 IP_ADDRESS: 192.168.0.2 # 常量模式
也可以说,以上4种模式最终都可以匹配到ipAddress这个属性名。为什么这样呢?原因就是在进行匹配时,配置中的名称要去掉中划线和下划线后,忽略大小写的情况下去与java代码中的属性名进行忽略大小写的等值匹配,以上4种命名去掉下划线中划线忽略大小写后都是一个词ipaddress,java代码中的属性名忽略大小写后也是ipaddress,这样就可以进行等值匹配了,这就是为什么这4种格式都能匹配成功的原因。不过springboot官方推荐使用烤肉串模式,也就是中划线模式。
注意:
@ConfigurationProperties绑定属性时支持属性名宽松绑定,这个宽松体现在属性名的命名规则上 @Value注解不支持松散绑定规则 绑定前缀名推荐采用烤肉串命名规则,即使用中划线做分隔符
六、常用计量单位绑定
在前面的配置中,我们书写了如下配置值,其中第三项超时时间timeout描述了服务器操作超时时间,当前值是-1表示永不超时。
servers: ip-address: 192.168.0.1 port: 2345 timeout: -1
但是每个人都这个值的理解会产生不同,比如线上服务器完成一次主从备份,配置超时时间240,这个240如果单位是秒就是超时时间4分钟,如果单位是分钟就是超时时间4小时。面对一次线上服务器的主从备份,设置4分钟,简直是开玩笑,别说拷贝过程,备份之前的压缩过程4分钟也搞不定,这个时候问题就来了,怎么解决这个误会?
除了加强约定之外,springboot充分利用了JDK8中提供的全新的用来表示计量单位的新数据类型,从根本上解决这个问题。以下模型类中添加了两个JDK8中新增的类,分别是Duration和DataSize
@Component @Data @ConfigurationProperties(prefix = "servers") public class ServerConfig { @DurationUnit(ChronoUnit.HOURS) private Duration serverTimeOut; @DataSizeUnit(DataUnit.MEGABYTES) private DataSize dataSize; }
Duration:表示时间间隔,可以通过@DurationUnit注解描述时间单位,例如上例中描述的单位为小时(ChronoUnit.HOURS)
DataSize:表示存储空间,可以通过@DataSizeUnit注解描述存储空间单位,例如上例中描述的单位为MB(DataUnit.MEGABYTES)
使用上述两个单位就可以有效避免因沟通不同步或文档不健全导致的信息不对称问题,从根本上解决了问题,避免产生误读。
Druation常用单位如下:
DataSize常用单位如下:
七、校验
目前我们在进行属性绑定时可以通过松散绑定规则在书写时放飞自我了,但是在书写时由于无法感知模型类中的数据类型,就会出现类型不匹配的问题,比如代码中需要int类型,配置中给了非法的数值,例如写一个“a",这种数据肯定无法有效的绑定,还会引发错误。 SpringBoot给出了强大的数据校验功能,可以有效的避免此类问题的发生。在JAVAEE的JSR303规范中给出了具体的数据校验标准,开发者可以根据自己的需要选择对应的校验框架,此处使用Hibernate提供的校验框架来作为实现进行数据校验。书写应用格式非常固定,话不多说,直接上步骤
步骤①:开启校验框架
步骤②:在需要开启校验功能的类上使用注解@Validated开启校验功能
@Component @Data @ConfigurationProperties(prefix = "servers") //开启对当前bean的属性注入校验 @Validated public class ServerConfig { }
步骤③:对具体的字段设置校验规则
@Component @Data @ConfigurationProperties(prefix = "servers") //开启对当前bean的属性注入校验 @Validated public class ServerConfig { //设置具体的规则 @Max(value = 8888,message = "最大值不能超过8888") @Min(value = 202,message = "最小值不能低于202") private int port; }
通过设置数据格式校验,就可以有效避免非法数据加载,其实使用起来还是挺轻松的,基本上就是一个格式。