SpringBoot中的配置文件有两种格式,properties和yaml/yml,一般情况下,两者可以随意使用,那么这两者是完全一样吗?肯定不是啦!之前我们了解了properties,这次我们来看看yaml配置,最后再来看看properties和yaml配置有什么区别。
1、位置问题
同样,application.yaml在SpringBoot中也有4个不同的位置,按照优先级分别为:
- 项目根目录下的config目录中;
- 项目根目录下;
- classpath下的config目录中;
- classpath目录下。
四个位置中的application.yaml文件的优先级按照上面列出的顺序依次降低,即如果有同一个属性在四个文件中都出现了,以优先级最高的为准。
默认情况下,SpringBoot启动时,默认会按照上面那4个位置顺序去查找相关属性并加载,但是,这也不是绝对的,我们也可以在项目启动时自定义配置文件。
例如,现在在resources目录下创建一个csconfig目录,目录中存放一个application.yaml文件,那么正常情况下,当我们启动项目时,这个配置文件是不会自动加载的。我们有两种方式指定配置文件位置,第一种可以通过spring.config.location属性来手动指定配置文件位置,第二种使用spring.config.additional-location这个属性,在第一个属性中,表示自己重新定义了配置文件的位置,项目启动时就按照定义的位置去查找配置文件,这种定义方式会覆盖掉默认的四个位置。也可以使用第二种方式,第二种方式表示在四个位置的基础上再添加几个位置,新添加的位置的优先级大于原本的位置。指定完成后,系统就会自动去指定目录下查找application.yaml文件。
此时启动项目,就会发现项目以classpath:/csconfig/application.yaml配置文件启动。
这是在开发工具中配置了启动位置,如果项目已经打包成jar,在启动命令中使用spring.config.location可以指定配置文件所在目录(注意需要以/结束),代码如下:
java -jar springbootdemo 0.0.1-SNAPSHOT.jar --spring.config.location=classpath:/csconfig/
2、文件名问题
对于application.yaml而言,它不一定非要叫application,但是项目默认是去加载名为application的配置文件,如果我们的配置文件不叫application,也是可以的,但是,需要明确指定配置文件的文件名。
方式和指定路径一致,只不过此时的key是spring.config.name。
首先我们在resources目录下创建一个app.yaml文件,然后在IDEA中指定配置文件的文件名。
指定完配置文件名之后,再次启动项目,此时系统会自动去默认的四个位置下面分别查找名为 app.yaml的配置文件。当然,允许自定义文件名的配置文件不放在四个默认位置,而是放在自定义目录下,此时就需要明确指定 spring.config.location或者spring.config.additional-location 。
配置文件位置和文件名称可以同时自定义。
如果项目已经打包成jar,在启动命令中使用如下命令,代码如下:
java -jar springbootdemo 0.0.1-SNAPSHOT.jar --spring.config.name=app --spring.config.location=classpath:/csconfig/
3、普通的属性注入
由于SpringBoot源自Spring,所以Spring中存在的属性注入,在SpringBoot中一样也存在。由于在SpringBoot中,默认会自动加载application.properties文件,所以简单的属性注入可以直接在这个配置文件中写。
例如,现在定义一个Book类:
package com.cs;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
public class Book {
private Integer id;
private String name;
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
然后在application.yaml文件中定义属性:
book:
id: 1
name: 三国演义
按照传统的Spring中的方式,可以直接通过@Value注解将这些属性注入到Book对象中,改造Book类:
package com.cs;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Book {
@Value("${book.id}")
private Integer id;
@Value("${book.name}")
private String name;
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
注意:
Book对象本身也要交给Spring容器去管理,如果Book没有交给Spring容器,那么Book中的属性也无法从Spring容器中获取到值。
配置完成后,在Controller或者单元测试中注入Book对象,启动项目,就可以看到属性已经注入到对象中了,单元测试代码如下:
package com.cs;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class BookTest {
@Autowired
Book book;
@Test
public void bookTest(){
System.out.println(book.toString());
}
}
4、类型安全的属性注入
SpringBoot引入了类型安全的属性注入,如果采用Spring中的配置方式,当配置的属性非常多的时候,工作量就很大了,而且容易出错。
使用类型安全的属性注入,可以有效地解决这个问题。
这里直接改在Book类:
package com.cs;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "book")
public class Book {
private Integer id;
private String name;
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这里主要引入了@ConfigurationProperties(prefix = “book”)注解,并且配置了属性的前缀,此时会自动将Spring容器中对应的数据注入到对象对应的属性中,就不用通过@Value注解挨个注入了,减少了工作量并且避免出错。
5、数组注入
yaml也支持数组注入,例如:
改造Book类:
package com.cs;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "book")
public class Book {
private Integer id;
private String name;
private List<Book> refers;
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", refers=" + refers +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Book> getRefers() {
return refers;
}
public void setRefers(List<Book> refers) {
this.refers = refers;
}
}
修改application.yaml文件:
book:
id: 1
name: 乱编书籍
refers:
- id: 11
name: 参考书籍1
- id: 22
name: 参考书籍2
启动测试类:
6、总结
不同于properties文件的无序,yaml配置是有序的,这一点在有些配置中是非常有用的,例如在Spring Cloud Zuul的配置中,当我们配置代理规则时,顺序就显得尤为重要了。当然,yaml配置也不是万能的,yaml配置目前不支持@PropertySource注解而properties支持。
本文参考:http://springboot.javaboy.org/2019/0416/spring-boot-yaml