java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot properties和yml区别、优先级、读取方式

SpringBoot配置文件之properties和yml的区别、优先级、读取方式

作者:小谢同学的小破站

还在为SpringBoot配置文件发愁,这篇文章用大白话讲清properties和yml的区别、优先级和读写方法,从改端口号到配置对象、List、Map,再到Hutool图形验证码实战,手把手教你避开yml空格坑,从此配置文件不再头疼,需要的朋友可以参考下

前言:

如果整篇只记一句话,我希望是这句:配置文件的本质,就是“把会变的东西从代码里挪出来”。而 SpringBoot 给了你两套写法——老派的 properties 和新潮的 yml,选哪个、怎么写、怎么读,这篇一次说清。

1. 配置文件是干嘛的?

先说个大白话结论:配置文件就是“把写死在代码里的东西拿出来,放到一个集中的地方”。
先说说什么叫“写死”(硬编码)。硬编码就是把数据直接嵌到程序源代码里,说白了就是“代码写死”。

也就是不能根据用户的需求来进行调整,就好像手机的字体大小一样,每个人的喜好都各不一样,如果采取了硬编码的形式来编写代码,只有我们程序员来设置字体大小,写死了,有些用户视力,以及个人习惯都不一样,这样用户的体验感就非常不好~
如果采用配置文件:把字号放在配置文件里,程序启动时读一下用户设置,按用户的偏好显示。这样能有效加强用户的体验感~

同样的道理,配置文件能让程序完成用户与应用程序的交互,也能完成应用程序与其他程序的交互。
那 SpringBoot 里,什么东西需要放到配置文件里?其实也就这几类:

配置内容为什么需要它
项目的启动端口SpringBoot 内置 Tomcat,默认 8080,但 8080 很可能被别的程序占了
数据库连接信息(url / 用户名 / 密码)每个项目连的数据库都不一样,持久层框架必须支持自定义
第三方系统的调用密钥不同环境、不同客户,密钥肯定不同
普通日志和异常日志用来发现和定位问题

顺便说一下 SpringBoot 在这件事上的另一层贡献:它定义并统一了配置文件的格式,其他框架想集成进 SpringBoot,必须得按它的规矩来。这就是“规范”带来的好处。

2. 快速入手:把 8080 改成 9090

前面说过,Tomcat默认的端口号是8080,例如,我们启动一个springboot项目:

如果当端口号被占用时,这时候程序启动就会失败,此时就需要修改启动时的端口号
spring项目在创建之初已经顺手帮我们建好了配置文件。打开 application.properties,改一行:

server.port=9090

重启程序观察日志:

端口号一定要选对。8080 常被 IDEA、其他 Java 进程、甚至微信开发者工具占着。启动报 Port 8080 was already in use 的时候,这时候不要急着怀疑代码,先去配置文件换个端口,或者改回来之前那个。

3. SpringBoot 支持的三种配置文件格式

SpringBoot 的配置文件一共有三种:

yml 是 yaml 的简写,实际开发中出现频率最高。yaml 和 yml 的用法完全一样,所以这里只来讲解 yml。
程序启动时,SpringBoot 会自动从 classpath 路径找到并加载这几个文件(application.properties、application.yaml 或 application.yml)。当然,也可以自己指定,比如通过 spring.config.name 参数来改名字和路径。

这就像商品的包装:

properties:是老款的包装
yml: 则是新款的包装

spring默认创建时生成的是老款包装:properties

这从而衍生出了一个面试题:yml和properties有什么区别?

说明内容
① 能共存吗?理论上 .properties 和 .yml 可以同时存在一个项目中,两个配置都会加载;如果内容冲突,以 .properties 为主,也就是 .properties 优先级更高
② 实际怎么用?虽然能共存,但真实业务里我们通常统一只用一种格式,这样更好维护,也能降低故障率

一句话记住优先级:properties > yml > yaml(同名冲突时)。

4. properties 配置文件说明

properties 是最早期的配置文件格式,也是创建 SpringBoot 项目时的默认格式。

4.1 基本语法

properties 是以键值对的形式配置的,key 和 value 之间用 = 连接:

例如:

# 配置项目端口号
server.port=8080
# 配置数据库连接信息
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

小技巧:配置文件中用 # 来添加注释信息。

4.2 读取配置:@Value

主动读取配置文件中的内容,可以用 @Value 注解。@Value 使用 ${} 的格式读取:
我们首先得在: application.properties 里先写一个自定义配置:

mykey.key1=helloWord

然后在 Controller 里读它:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PropertiesController {

    @Value("${mykey.key1}")
    private String key1;

    @RequestMapping("/key")
    public String key() {
        return "读取到值:" + key1;
    }
}

浏览器访问 /key,就能看到 读取到值:helloWord。

${} 里写的是配置文件的 key 全名,别写成 Java 字段名。字段叫 key1,但配置里是 mykey.key1,写错了启动就报 Could not resolve placeholder。

4.3 properties 的缺点

properties 是 key-value 的形式,好处是简单,坏处是——冗余信息特别多。
当我们配置文件中写的特别多的时候,看起来就很冗余,让人看起来就不是特别的简洁明了,感觉看起来一坨一坨的,不方便程序员理解;
我们来看上面那段数据库配置,spring.datasource 被重复写了三遍:

spring.datasource.url=...
spring.datasource.username=...
spring.datasource.password=...

配置项一多,这种重复就爆炸式增长,我们想要去修改个前缀还得全局替换一遍。
此时yml就能很好的解决冗余的问题,yml天生就是树形结构有很强的可读性

5. yml 配置文件说明

yml 是 YAML 的缩写,全称 Yet Another Markup Language,翻译过来就是“另一种标记语言”。名字很谦虚,格式很好用。

5.1 基本语法

yml 是树形结构的配置文件,基础语法是 key: value。

注意:key 和 value 之间使用英文冒号加空格的方式组成,冒号后面的空格是一定不可以省略!

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/dbname?characterEncoding=utf8&useSSL=false
    username: root
    password: root

第一项(spring: 带空格)是正确写法,key 在 IDEA 里会高亮显示;如果写成 spring:datasource 少了空格,key 就不会高亮,配置也不会生效。

两者的对比:

对比项propertiesyml
写法spring.datasource.url=... 平铺spring: 换行缩进,树形
层级表达靠 . 点号连接靠换行 + 缩进
前缀重复每行都要重复写 spring.datasource只写一次,子项缩进即可
可读性一般更好,一眼看出层级关系

注意: yml 里 key: 后面必须跟一个空格。server:port 不会报错弹窗,但配置就是不生效,排查半天你才会发现少了个空格。-> 一个空格引发的惨 案。

我们需要添加一个空格才能是yml文件进行生效:

5.2 使用进阶

 yml 支持的数据类型比 properties 丰富,字符串、布尔、整数、浮点、null、空串都能写:

5.2.1 配置不同数据类型及 null

例如:

# 字符串
string.value: hello
# 布尔值,true 或 false
boolean.value: true
boolean.value1: false
# 整数
int.value: 10
# 浮点数
float.value: 3.14159
# Null,~ 代表 null
null.value: ~
# "" 空字符串
# 直接后面什么都不加也可以,但这种写法不直观,更推荐用引号括起来
empty.value: ''
类型写法备注
字符串string.value: Hello默认不用加引号
布尔值true / false只能小写
整数int.value: 10—
浮点数float.value: 3.14159—
nullnull.value: ~~ 就是 null
空字符串empty.value: ''推荐用引号,直观看得出来

读取方式和 properties 一模一样,还是 @Value:

@RestController
public class ReadYml {
    @Value("${string.value}")
    private String hello;

    @RequestMapping("/ymlKey")
    public String key() {
        return "读取到值:" + hello;
    }
}

访问 http://127.0.0.1:8080/ymlKey,输出 读取到值:hello。

5.2.2 单引号与双引号

字符串默认不用加单引号或双引号,但如果加了英文的单双引号,就表示特殊的含义。我们在 application.yml 里配置三段:

string:
  str1: Hello \n Spring Boot.
  str2: 'Hello \n Spring Boot.'
  str3: "Hello \n Spring Boot."

读取代码:

@RestController
public class ReadYml {
    @Value("${string.str1}")
    private String str1;
    @Value("${string.str2}")
    private String str2;
    @Value("${string.str3}")
    private String str3;

    @RequestMapping("/yml")
    public String readYml() {
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);
        return "yml";
    }
}

我们能观察到一下结果:

详细:

Hello \n Spring Boot.      ← str1:不加引号,\n 就是个普通字符
Hello \n Spring Boot.      ← str2:单引号,\n 被转义,还是普通字符
Hello                       ← str3:双引号,\n 保持本意,真的换行
 Spring Boot.

结论整理成一句话:单引号会把 \n 转义掉(变成普通字符串,不换行),双引号不转义(\n 表示它本身的含义,也就是换行)。

写法\n 的表现结果
不加引号按普通字符处理原样输出 Hello \n Spring Boot.
单引号 '...'转义,失去特殊功能原样输出 Hello \n Spring Boot.
双引号 "..."不转义,保留本意真的换行

这里的“转义”确实拗口,但记住一句话就行:单引号是“保护套”,把特殊字符保护起来当普通人;双引号是“放大器”,让特殊字符继续发挥它的特殊能力。

5.2.3 配置对象

yml 里还可以直接配置一个对象,接下来我们来看一看如何来配置对象:
我们首先定义好对象的属性:

@Data
public class Student {
    private int id;
    private String name;
    private int age;
}

@Data注解,在之前的文章中我们谈到过,这是一个工具类,方便我们程序员的开发,我们不需要自己写get和set方法等

student:
  id: 1
  name: Java
  age: 18

或者用行内写法(和上面作用一致):

student: {id: 1,name: Java,age: 18}

注意:这个时候我们就不能再去使用 @Value 去读了(一个个字段读太麻烦),要用@ConfigurationProperties:而不是使用@Value注解

@ConfigurationProperties(prefix = "student")
@Component
@Data
public class Student {
    private int id;
    private String name;
    private int age;
}

调用类:

@RestController
public class StudentController {
    @Autowired
    private Student student;

    @RequestMapping("/readStudent")
    public String readStudent() {
        return student.toString();
    }
}

访问 http://127.0.0.1:8080/readStudent,就能看到 Student(id=1, name=Java, age=18)。

  1. @ConfigurationProperties 只是“说明怎么绑定”,这个类必须被 Spring 管理才会生效,所以要加 @Component(或者在启动类上加 @EnableConfigurationProperties)。
  2. prefix 的值要跟配置文件的第一层 key 完全一致,而且建议全小写。写成 prefix = "Student" 或者 prefix = "student.id" 都会绑定失败,字段全是默认值。

5.2.4 配置集合 List

配置文件里当然也能配 List:
例如:

dbtypes:
  name:
    - hello
    - word
    - hi

集合的读取和对象一样,还是使用 @ConfigurationProperties注解:

@Component
@ConfigurationProperties("dbtypes")
@Data
public class ListConfig {
    private List<String> name;
}

访问的方式:

@RestController
public class ReadYml2 {

    @Autowired
    private ListConfig listConfig;

    @RequestMapping("/readList")
    public String readList() {
        return listConfig.toString();
    }
}

访问 http://127.0.0.1:8080/readList

5.2.5 配置 Map

同理,配置文件中Map 也能够配置:
例如:

maptypes:
  map:
    k1: hello
    k2: word
    k3: hi

map在配置文件中是使用键值对形似的,前面是key,后面为value

或者行内写法(作用一致):

maptypes: {map: {k1: kk1,k2: kk2, k3: kk3}}

Map 的读取还是同样用 @ConfigurationProperties 注解:

@Data
@ConfigurationProperties(prefix = "maptypes")
@Component
public class MapConfig {
    private HashMap<String, String> map;
}

浏览器获取结果:

@Data
@ConfigurationProperties(prefix = "maptypes")
@Component
public class MapConfig {
    private HashMap<String, String> map;
}

访问 http://127.0.0.1:8080/readMap

小结:@Value 只能读“单个值”,一旦遇到**对象 / List / Map 这种复杂结需要使用@ConfigurationProperties。

5.3 yml 的优缺点

我们先来看看yml文件的优点:

  1. 可读性高,写法简单,易于理解;
  2. 支持更多的数据类型,可以简洁地表达对象、数组、List、Map 等数据形态;
  3. 支持更多的编程语言,不止 Java,Golang、Python、Ruby、JavaScript 里也能用。

缺点:

  1. 不适合写复杂的配置文件。

例如我们先来看看这段配置文件:

keycloak.realm = demo
keycloak.resource = fm-cache-cloud
keycloak.credentials.secret = d4589683-Oce7-4982-bcd3
keycloak.security[0].authRoles[0]= user
keycloak.security[0].collections[0].name = ssologinurl
keycloak.security[0].collections[0].patterns[0] = /login/*

转成 yml 就变成这样:

keycloak:
  realm: demo
  resource: fm-cache-cloud
  credentials:
    secret: d4589683-Oce7-4982-bcd3
  security:
    - authRoles:
        - user
      collections:
        - name: ssologinurl
          patterns:
            - /login/*

转换过程本身就挺费精力,如果我们的配置再复杂一点,可读性会变得更差,代码也更难写。

  1. 对格式有很强的要求,一个空格可能会引起一场血 案。

排查半天发现少写了一个空格~

总结与速查清单

核心三句话:

  1. 配置文件 = 把会变的信息从代码里挪出来,解决硬编码问题;
  2. properties 是 key=value 的键值形式,yml 是树形结构,靠缩进表达层级;
  3. 单个值用 @Value,对象 / List / Map 用 @ConfigurationProperties。

properties vs yml 速查

对比项propertiesyml
语法key=valuekey: value(冒号后必须有空格)
结构平铺,靠 . 连接树形,靠换行缩进
注释##
冗余多(前缀重复写)少(同层只写一次)
数据类型基本类型字符串/布尔/数字/null/对象/List/Map
适用场景简单配置、老项目日常开发首选
复杂度容忍度高(复杂配置更清楚)低(复杂配置可读性差)

Value 与ConfigurationProperties应该选哪一个?

注解写法能读什么备注
@Value@Value("${key}")单个值(String、int…)读不了对象 / List / Map
@ConfigurationProperties@ConfigurationProperties(prefix = "xxx")对象、List、Map、嵌套结构类必须被 Spring 管理(加 @Component)

注意事项:

坑表现解决
yml 冒号后漏空格配置不生效,key 不高亮写成 port: 9090 这种“冒号 + 空格”的形式
@Value 里写字段名Could not resolve placeholder写配置里的 key 全名,如 ${mykey.key1}
@ConfigurationProperties 类没被管理字段全是默认值(0 / null)加 @Component
prefix 大小写不对绑定失败建议全小写,和 yml 第一层 key 一致
properties 和 yml 冲突生效的是 properties只用一种格式,别两个都留
单引号里的 \n不换行想要换行就用双引号

以上就是 SpringBoot 配置文件的全部内容啦,从“为什么要有配置文件”一直写到“验证码实战”

以上就是SpringBoot配置文件之properties和yml的区别、优先级、读取方式的详细内容,更多关于SpringBoot properties和yml区别、优先级、读取方式的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文