Spring Boot 的配置文件
- [一 . 配置文件作用](#一 . 配置文件作用)
- [二 . 配置文件的格式](#二 . 配置文件的格式)
-
- [2.1 Spring Boot 项目创建重新演示](#2.1 Spring Boot 项目创建重新演示)
- [2.2 .yml](#2.2 .yml)
- [2.3 为什么要用两种配置文件呢 ?](#2.3 为什么要用两种配置文件呢 ?)
- [三 . properties 配置文件说明](#三 . properties 配置文件说明)
-
- [3.1 基本语法](#3.1 基本语法)
- [3.2 读取配置文件](#3.2 读取配置文件)
- [3.3 properties 优缺点](#3.3 properties 优缺点)
- [四 . yml 配置文件说明](#四 . yml 配置文件说明)
- [五 . properties VS yml](#五 . properties VS yml)
- [六 . 解决 properties 乱码问题](#六 . 解决 properties 乱码问题)
- [七 . 多平台的配置文件设置](#七 . 多平台的配置文件设置)
这个专栏给大家介绍一下 Java 家族的核心产品 - SSM 框架
JavaEE 进阶专栏Java 语言能走到现在 , 仍然屹立不衰的原因 , 有一部分就是因为 SSM 框架的存在
接下来 , 博主会带大家了解一下 Spring、Spring Boot、Spring MVC、MyBatis 相关知识点
并且带领大家进行环境的配置 , 让大家真正用好框架、学懂框架
来上一篇文章复习一下吧
点击即可跳转到我的小秘密
一 . 配置文件作用
整个项目中所有重要的数据都是在配置文件中配置的 , 比如 :
- 数据库的连接信息(包含用户名和密码的设置)
- 项目的启动端口
- 第三方系统的调用密钥等信息
- 用于发现和定位问题的普通日志和异常日志等
如果没有配置信息 , 那么 Spring Boot 项目就不能连接和操作数据库 , 甚至是不能保存可以用于排查问题的关键日志 , 所以配置文件的作用非常重要 !
二 . 配置文件的格式
Spring Boot 配置文件主要分为以下两种格式 :
- .properties
- .yml
我们 Spring Boot 项目本身不是自带配置文件吗
其实我们还可以自己创建配置文件
我们新建一个项目给大家重新演示一下
2.1 Spring Boot 项目创建重新演示
File -> New -> Project
选择 Sping Initializr , 选择 JDK 版本为 1.8 , 选择默认的 start.spring.io
假如有一天 Spring 项目创建失败 , 我们该怎么做 ?
- 有可能是官网问题(可能性不大) : 耐心等待即可
- 有可能是运营商问题 : 我们提前在官网创建一个 Spring Boot 项目 , 下载下来 , 留作备用
- 也可以直接把之前的 Spring Boot 项目复制一份 , 在 IDEA 里面打开 , 把之前写过的业务代码删除即可
更改 Project type 为 Maven , Java version 版本为 8
首先选择 Developer Tools , 然后选择上面的版本号(如果大家有 2.6.13 版本的就选择 2.6.13 版本的) , 然后选择图片里面的两个
再选择 Web 里面的 Spring Web
然后 Next
我们需要点击项目名 , 然后右键 , Add Framework Support
选择 Maven , 点击 Ok
然后再把一些没有用的删除掉
之后检验一下项目是否创建成功
在 application.properties 里面 , 我们还可以更改端口号
配置文件文件名问题
我们之前介绍过 , 在 Spring Boot 里面 , 约定大于配置
那么这个配置文件的名字也不能瞎填
启动是没问题的 , 但是配置文件没生效
如果你想要配置文件是一个有效的文件 , 就需要严格控制配置文件名 , 我们只支持 application 开头的 , 以 .properties 或者 .yml 为后缀的配置文件
如果面试官问你 : Spring Boot 有什么特点啊 ?
你就可以回答一个约定大于配置 , 然后面试官问你 : "那你举个栗子吧"
你就可以这样解释了
2.2 .yml
我们通过 .properties 成功更改了端口号 , 那 .yml 呢 ?
起名叫做 application.yml
然后运行一下吧 , 也是可以更改端口的
不过这个方法很容易发生错误
那我们把空格删掉呢
2.3 为什么要用两种配置文件呢 ?
假如我们在 application.properties 里面设置端口号为 9090 , 在 application.yml 里面设置端口号为 9091 , 那么最后端口号到底是 9090 还是 9091 呢 ?
这其实就像是我们的学校的校服 , .properties 代表老一版的校服 , 是教育局让做成这样的 . .yml 就代表新一版的校服 , 是学校自己制作的 . 那么领导检查 , 你说穿哪个 ? 肯定是穿 .properties 的校服啊 , 所以 Spring Boot 要去听 .properties 的 .
那么我们总结一下 :
- 理论上讲 .properties 可以和 .yml ⼀起存在于⼀个项目当中 , 当 .properties 和 .yml ⼀起存在⼀个项目中时 , 如果配置文件中出现了同样的配置 , 比如 .properties 和 .yml 中都配置了 "server.port" , 那么这个时候会以 .properties 中的配置为主 , 也就是 .properties 配置文件的优先级最高 , 但加载完 .properties 文件之后 , 也会加载 .yml 文件的配置信息
- 虽然理论上来讲 .properties 可以和 .yml 共存,但实际的业务当中,我们通常会采取⼀种统⼀的配置文件格式,这样可以更好的维护 (降低故障率) . 这就比如我们的校服 , 那肯定只能穿一个 , 不能一次穿两个吧 .
三 . properties 配置文件说明
properties 配置文件是最早期的配置文件格式,也是创建 Spring Boot 项目默认的配置文件
3.1 基本语法
首先 , 我们 .properties 里面的注释是 # 开头
yaml
# 设置端口号
server.port=9090
# 设置数据库的连接信息
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/myblog2023?characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
这些设置我们也可以在这个网站里面找到
Common Application Properties
需要配置谁的时候 , 去这里面找一下即可
那假如我们不想使用官方的 , 我们想要用自己写的配置呢 ?
那我们就需要给大家介绍一下配置文件内容的分类了
配置文件内容分类
- Spring Boot (Spring) 内置的配置项 , 比如 server.port
- 用户自定义的配置项
3.2 读取配置文件
如果在项目中 , 想要主动的读取配置文件中的内容 , 可以使用 @Value 注解来实现
我们新建一个 TestController 类来试验一下
TestController.java
java
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 这个注解什么意思先不用管
@RestController
public class TestController {
// 先接收用户自己的
@Value("mykey.key1")
private String mykey;
// 这个注解什么意思先不用管
@RequestMapping("/hi")
public String sayHi() {
return "Hi," + mykey;
}
}
运行之后 , 来看一下结果
那这可不对劲 , 我的配置文件里面是 ethan 啊
那么要注意 : @Value 注解使用"${}"的格式读取
把要读取的 key 放在花括号里
运行一下 , 看一下结果
这回就把 ethan 成功读取出来了
那么我们刚才读取的是用户自定义的配置项 , 那么能不能读取系统的配置项呢 ?
java
package com.example.demo.aa.bb;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 这个注解什么意思先不用管
@RestController
public class TestController {
// 用户自己的配置项
@Value("${mykey.key1}")
private String mykey;
// 接收系统的配置项
@Value("${server.port}")
private Integer port;
// 这个注解什么意思先不用管
@RequestMapping("/sayhi")
public String sayHi() {
return "Hi," + mykey + ",您的端口号为:" + port;
}
}
3.3 properties 优缺点
优点 : 写法简单 , 不易出错 , 等号前面是 key , 等号后面是 value
缺点 : 写法不够灵活和简便 , 如数据库的配置 , 同样的前缀写了三遍
四 . yml 配置文件说明
yml 是 YAML 的缩写 , 它的全称 Yet Another Markup Language , 翻译成中文就是 "另⼀种标记语言" , 我们把后缀改成 .yaml 运行也不报错
他的优点有 :
- yml 可读性高 , 写法简单、易于理解 , 它的语法和 JSON 语言类似
- yml 支持更多的数据类型 , 它可以简单表达数组 (清单)、散列表 , 标量等数据形态 . 它使用空白符号缩进和大量依赖外观的特色 , 特别适合用来表达或编辑数据结构、各种配置文件等
- yml 支持更多的编程语言,它不止是 Java 中可以使用 , 在 Golang、PHP、Python、Ruby、JavaScript、Perl 中同样可以使用
那为什么 yml 要支持这么多的编程语言呢 ?
我们的字节跳动 , 旗下有抖音、今日头条、西瓜视频等产品 , 假如我们的抖音是 Golang 语言设计的 , 今日头条是 PHP 语言设计的 , 西瓜视频是 Python 设计的 , 我们现在有一个业务 : 用户忘记账号 , 我们可以展示给用户手机号 . 那么我们就可以读取配置文件里面存储的手机号 , 如果是统一的 yml 配置文件 , 我们只需要按照要求去修改一次就可以了 . 那要是每个语言都有自己的配置文件呢 ? 每个都去修改未免也太麻烦
4.1 基本语法
yml 是树形结构的配置文件 , 它的基础语法是 : "key:** **value" , 注意 key 和 value 之间使用冒号加空格的方式组成的 , 其中的空格不可省略
那么我们的 yml 又分成了一级目录和多级目录
一级目录 :
yaml
key: value
二级目录 :
yaml
key:
key2:
key3: value
那么我们通过数据库连接来看一下多级目录的系统配置项是怎么回事
yaml
# 一级目录
# 用户自定义配置项
mystring: ethan888
# 多级目录
# 系统配置项(数据库连接)
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/myblog2023?characterEncoding=utf8
username: root
password: root
4.2 读取配置文件
跟之前 .properties 读取配置文件的方法一样
java
package com.example.demo.aa.bb;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 这个注解什么意思先不用管
@RestController
public class TestController {
// 接收系统的配置项
@Value("${spring.datasource.password}")
private String password;
// 接收用户的配置项
@Value("${mystring}")
private String mystring;
// 这个注解什么意思先不用管
@RequestMapping("/sayhi")
public String sayHi() {
return "Hi," + mystring + ",您的数据库密码为:" + password;
}
}
运行一下
4.3 yml 使用进阶
4.3.1 yml 配置不同数据类型及 null
yaml
# 字符串
string.value: Hello
# 布尔值,true或false
boolean.value1: true
boolean.value2: false
# 整数
int.value1: 10
int.value2: 0b1010_0111_0100_1010_1110 # ⼆进制
# 浮点数
float.value1: 3.14159
float.value2: 314159e-5 # 科学计数法
# Null,~代表null
null.value: ~
4.3.2 注意事项:value 值加单双引号
yaml
string:
str1: Hello \n Spring Boot.
str2: 'Hello \n Spring Boot.'
str3: "Hello \n Spring Boot."
TestController.java
java
package com.example.demo.aa.bb;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 这个注解什么意思先不用管
@RestController
public class TestController {
@Value("${string.str1}")
private String str1;
@Value("${string.str2}")
private String str2;
@Value("${string.str3}")
private String str3;
// 这个注解什么意思先不用管
@RequestMapping("/sayhi")
public String sayHi() {
System.out.println("str1:" + str1);
System.out.println("str2:" + str2);
System.out.println("str3:" + str3);
return "测试配置文件里面 value 加不同引号的问题";
}
}
查看一下运行结果
这也没发生什么啊 ?
再回编译器瞅瞅
下面打印出了结果 , 我们来看一下
str1:Hello \n Spring Boot.
str2:Hello \n Spring Boot.
str3:Hello
Spring Boot.
str3 产生了换行效果 , 这说明了什么 ?
当我们设置 value 值的时候 , 如果我们加了双引号 , 双引号里面的特殊字符就会发出它本来的作用
4.3.3 配置对象
虽然这个场景比较少 , 但是不代表他就没有 , 就比如我们的消防通道 , 可以不用但是他不能没有 .
我们其实之前也见到过配置对象
yaml
# 多级目录的系统配置项(数据库连接)
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/myblog2023?characterEncoding=utf8
username: root
password: root
其实我们的 datasource 就是一个对象
那么接下来给大家介绍在配置文件里面存储对象或者取出对象的写法
原始写法
yaml
student:
id: 123
name: anlingrong
age: 21
那么我们怎么去读他呢 ?
我们还是可以通过之前的方法来去读取他
java
package com.example.demo.aa.bb;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 这个注解什么意思先不用管
@RestController
public class TestController {
@Value("${student.id}")
private Integer id;
@Value("${student.name}")
private String name;
@Value("${student.age}")
private Integer age;
// 这个注解什么意思先不用管
@RequestMapping("/sayhi")
public String sayHi() {
System.out.println("id:" + id);
System.out.println("name:" + name);
System.out.println("age:" + age);
return "Hi," + name
+ ",你的学号为:" + id
+ ",您的年龄为:" + age;
}
}
那假如我们的配置对象有 90000 个属性呢 ?
那通过这种方式 , 就是吃力不讨好 , 得写 90000 个 @Value , 所以我们需要了解一下简便的方法
我们在 com.example.demo 包底下新建一个包 , 叫做 model , 然后在 model 包底下新建一个 Student 类
java
package com.example.demo.model;
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
我们需要添加两个注解
- @Component : 代表我们项目运行的时候 , 带有此注解的标签就会先把配置文件里面的信息加载到该类里面
- @ConfigurationProperties(prefix = "student") : 意思是我们需要加载配置文件里面的哪个对象
那么这一番操作下来 , 我们的对象就存储到 Spring 里面了
接下来 , 我们可以去获取 Spring 里面的对象了
java
package com.example.demo.model;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "student")//将配置文件里面的 student 配置赋值给当前的对象
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
TestController.java
java
package com.example.demo.aa.bb;
import com.example.demo.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 这个注解什么意思先不用管
@RestController
public class TestController {
@Autowired
private Student student;
// 这个注解什么意思先不用管
@RequestMapping("/sayhi")
public String sayHi() {
return "Hi," + student.getName()
+ ",你的学号为:" + student.getId()
+ ",您的年龄为:" + student.getAge();
}
}
运行一下
成功读取到了
但是这里面有几个注意事项
- 我们的 setName setAge setId 删掉了 , 那程序还能执行吗 ?
java
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
看到这样的错误 , 抓紧去干一件事 , 立刻马上 !
在 application.properties 里面写上 debug=true , 这样控制台给我们的错误信息就会多了
重新运行
看这条报错信息
意思就是 : 绑定失败 , 实际上就是缺少 setter 方法
读取配置文件的实体类不能没有 setter 方法 , 我们的 @ConfigurationProperties(prefix = "student") 在实现的时候 , 是调用这个类里面的 setter 方法将配置文件中的内容来赋值给字段的 , 没有 setter 方法 , 程序启动直接报错 .
- @ConfigurationProperties 需要配合注册五大类注解使用 , 如 @Component 注解一起使用
行内写法
yaml
# 对象的行内写法
student2: {id: 456,name: shenmeizhuang,age: 18}
# 我们要写 value 的话就需要加空格
来看例子吧
Student.java
java
package com.example.demo.model;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "student2")//将配置文件里面的 student 配置赋值给当前的对象
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
然后 TestController.java 不用动
运行一下
4.3.4 配置集合
对象往上升一级 , 就是集合了 . 学完了对象之后 , 学习集合的写法就非常简单了 .
配置集合还是有两种写法 :
原始写法
yaml
# 集合外层名字(相当于类名)
mylist:
# name 属性用来接收多个值
dbtype:
- mysql
- sqlserver
- db2
# - 相当于 Markdown 里面的无序列表
那么我们先在 application.yml 里面把集合写进去
然后在 model 包底下新建一个类(这个类起到的作用就是容器作用) , 叫做 MyList
大家记不记得我们之前添加过 Lombok , 我们就可以通过 Lombok 来替换掉 Getter 和 Setter 方法
我们还可以把注解替换成 @Getter 和 @Setter , 这两个注解意思就是替我们写了 Getter Setter 方法了
java
package com.example.demo.model;
import lombok.Data;
import java.util.List;
@Data
public class MyList {
public List dbtype;
}
接下来 , 我们需要读取配置文件里面的某一个 key 的 , 通过 @ConfigurationProperties(prefix = "mylist") , 读取配置文件里面的 mylist 属性里面的 dbtype 放到类里面的 dbtype 属性里面 .
之后 , 如果我们想要在其他类里面去使用的话 , 我们需要把这个对象注入到 Spring 里面 , 所以要加上 @Component 注解
MyList.java
java
package com.example.demo.model;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Data
@Component
@ConfigurationProperties(prefix = "mylist")
public class MyList {
public List dbtype;
}
然后我们编写 TestController.java
java
package com.example.demo.aa.bb;
import com.example.demo.model.MyList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 这个注解什么意思先不用管
@RestController
public class TestController {
@Autowired
private MyList myList;
// 这个注解什么意思先不用管
@RequestMapping("/sayhi")
public String sayHi() {
return "集合的大小:" + myList.getDbtype().size()
+ ",集合的第一个元素" + myList.getDbtype().get(0);
}
}
运行一下
找到了 3 个值 , 第一个值为 MySQL
行内写法
yaml
mylist2: {dbtype:[MySQL, SQL Server,db2]}
运行一下
注意一点 :
我们的 MyList 类里面的属性名不能瞎起 , 必须是在配置文件里面存在
五 . properties VS yml
- properties 是以
key=value
的形式配置的键值类型的配置文件 , 而 yml 使用的是类似 json 格式的树形配置方式进行配置的 , yml 层级之间使用换行缩进的方式配置 , key 和 value 之间使用冒号+空格
( ": " )的方式设置 , 并且空格不可省略 . - properties 为早期并且默认的配置文件格式 , 但其配置存在⼀定的冗余数据 , 使用 yml 可以很好的解决数据冗余的问题。
- yml 通用性更好 , 支持更多语言 , 如 Java、Go、Python 等,如果是云服务器开发,可以使用一份配置文件作为 Java 和 Go 以及其他语言的共同配置文件
- yml 虽然可以和 properties 共存 , 但⼀个项目中建议使用统⼀的配置类型文件
六 . 解决 properties 乱码问题
我们之前在 application.properties 里面配置过一些信息 , 写过一些注释 , 是中文的 , 但是下一次再打开就乱码了 ?
这是因为我们写进去的汉字是 Utf8 , 但是 .properties 字符集默认是 ISO-8859-1 编码格式 , 字符编码格式不统一就变成乱码了
那怎么解决呢 ?
我们就需要设置当前项目和新项目编码格式为 Utf8
接下来我们试验一下更改字符集成没成功
关掉再开开
目前我们只是设置了当前项目的编码格式 , 接下来我们需要设置新项目的编码格式
这样的话我再新建项目 , 再也不用担心字符乱码问题了 . 但是之前已经乱码的地方 , 已经无法挽回了 .
七 . 多平台的配置文件设置
我们之前介绍过 , Spring Boot 虽然有两个版本的配置文件 , 但是我们在项目中 , 只会使用一个 . 而且在公司中开发环境非常复杂 , 配置文件也有多个平台的 . 一般分为三个
- 开发环境的配置文件
- 测试环境的配置文件
- 生产环境的配置文件
- ...
所以我们通过这样的方式 , 是显然不行的
在公司里面 , 我们会去创建不同环境的配置文件
那么我们就会创建三个配置文件 : application-环境名称.yml
- 开发环境的配置文件 : application-dev.yml
- 测试环境的配置文件 : application-test.yml
- 生产环境的配置文件 : application-prod.yml
我们在里面也设置了一些信息 , 这些信息是基本不会动的
然后我们就可以在总配置文件去设置运行环境
yaml
# 运行环境设置
spring:
profiles:
active: dev
这段代码的意思是我们设置的环境是开发环境
因为我们不同的环境的配置文件设置的端口号不同
通过查看端口号就知道我们运行环境设置是不是成功了