1. 配置文件格式

SpringBoot配置文件格式支持后缀名为.yml.properties两种格式的文件。后缀名为.yml的文件是通过YAML语法编写;

@@注意:   如果application.ymlapplication.properties两个文件同时存在相同的路径下,则优先使用application.properties配置文件的内容。关于配置文件的加载优先级,后面小节详细归纳。

2. 准备测试条件

为了方便验证配置文件中的值是否能被正确读取到,新建立Person类和Job类,以备后续使用。最终效果是通过配置文件设置这两个类的属性值。

2.1 创建Job类

新建文件: Job.java
文件位置: src/main/java/com/hui/configfile/bean/Job.java

package com.hui.configfile.bean;

import lombok.Data;
import org.springframework.stereotype.Component;

@Data
@Component
public class Job {
private String jobName;
private Integer jobAge;
@Override
public String toString() {
return "Job{" +
"jobName='" + jobName + '\'' +
", jobAge=" + jobAge +
'}';
}
}

2.2 创建Person类

新建文件: Person.java
文件位置: src/main/java/com/hui/configfile/bean/Person.java

package com.hui.configfile.bean;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;
@Data
@Component
public class Person {
private String name;
private Integer age;
private Boolean isBoy;
private Date birthday;
private Map<String,Object> other;
private List<String> likes;
private Job job;

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
", isBoy=" + isBoy +
", other=" + other.toString() +
", likes=" + likes.toString() +
", job =" + job.toString() +
'}';
}
}

2.3 引入配置文件处理器

导入配置文件处理器,配置文件进行绑定就会有提示

<dependency> 
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐configuration‐processor</artifactId>
<optional>true</optional>
</dependency>

效果如下:

image-20201014161118467

3. 注入到对象(@ConfigurationProperties)

3.1 使用(application.yml)

修改文件: application.yml

server:
port: 8001
person:
# 字符串类型
name: 张三
# 数字类型
age: 25
# 日期类型
birthday: 1996/11/23
# 布尔类型
is-boy: true
# Map类型
other: { home: 北京, phone: 17600000000 }
# List类型
likes:
- 游戏
- 动漫
- 游泳
# 对象类型
job:
jobName: 开发工程师
job-age: 3

上述配置中is-boy也可以写成: isBoy

3.1.1 注入对象

为了方便验证Yaml值的写法和赋值效果,修改Person对象,使@ConfigurationProperties用来加载配置文件的内容;

@ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定,prefix = "person":配置文件中哪个下面的所有属性进行一一映射

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
@Data
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
....
}

3.1.2 测试代码

package com.hui.configfile;

import com.hui.configfile.bean.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ConfigFileApplicationTests {
@Autowired
Person person;
@Test
void contextLoads() {
System.out.println(person);
//输出: Person{name='张三', age=25, birthday=Sat Nov 23 00:00:00 CST 1996, isBoy=true, other={home=北京, phone=17600000000}, likes=[游戏, 动漫, 游泳], job =Job{jobName='开发工程师', jobAge=3}}
}
}

3.2 使用(application.properties)

修改文件:application.properties

server.port=8002
# 字符串类型
person.name=小美
# 数字类型
person.age=21
# 布尔类型
person.is-boy=false
# Map类型
person.other.home=北京
person.other.phone=110110110
# List类型
person.likes=游戏,动漫,游泳
# 日期类型
person.birthday=2022/05/17
# 对象类型
person.job.jobName=模特
person.job.jobAge=2

3.2.1 注入并测试

配置绑定到对象代码同(3.1.1 注入对象) 测试代码同(3.1.2 测试代码)

输出乱码:

Person{name='小美', age=21, birthday=Tue May 17 00:00:00 CST 2022, isBoy=false, other={home=北京, phone=110110110}, likes=[游戏, 动漫, 游泳], job =Job{jobName='模特', jobAge=2}}

properties配置文件在idea中默认utf-8会乱码,如上输出。可进行以下调整

配置File Encodings

image-20201012161903172

如果IDEA版本是2020的,上面设置以后,控制台输出还是乱码,还需要进行以下配置

设置 Additional command line parameters选项为 -encoding utf-8,如下图:

image-20201012162013106

设置后执行输出:

Person{name='小美', age=21, birthday=Tue May 17 00:00:00 CST 2022, isBoy=false, other={home=北京, phone=110110110}, likes=[游戏, 动漫, 游泳], job =Job{jobName='模特', jobAge=2}}

3.3 使用@PropertySource

@PropertySource: 加载指定文件,

把上面有关Person的配置信息,单独移到一个文件;这样以来就能和框架常用配置区分开。

3.3.1 提取到单独文件

新建文件: src/main/resources/person.properties

# 字符串类型
person.name=王麻子
# 数字类型
person.age=21
# 布尔类型
person.is-boy=true
# Map类型
person.other.home=湖南
person.other.phone=1611090000000
# List类型
person.likes=赌博,泡妞
# 日期类型
person.birthday=1992/05/17
# 对象类型
person.job.jobName=无业游民
person.job.jobAge=0

3.3.2 修改Person类

package com.hui.configfile.bean;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;
@Data
@Component
// 指定加载文件位置
@PropertySource(value = "classpath:person.properties")
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private Boolean isBoy;
private Date birthday;
private Map<String,Object> other;
private List<String> likes;
private Job job;

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
", isBoy=" + isBoy +
", other=" + other.toString() +
", likes=" + likes.toString() +
", job =" + job.toString() +
'}';
}
}

3.3.3 编写测试代码

package com.hui.configfile;

import com.hui.configfile.bean.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class testPerson {
@Autowired
private Person person;

@Test
void run(){
System.out.println(person);
}
}

/* 输出:
Person{name='王麻子', age=21, birthday=Sun May 17 00:00:00 CST 1992, isBoy=true, other={home=湖南, phone=1611090000000}, likes=[赌博, 泡妞], job =Job{jobName='无业游民', jobAge=0}}
*/

4.@Value使用

4.1 使用方式

@Value的常见的使用方式如下:

  • 注入普通字符串
  • 注入配置属性
  • 注入系统变量
  • 使用SpEL表达式
  • 注入其他bean的属性
  • 注入文件资源
  • 注入网页资源

具体使用代码如下:

TestValue.java: 用于演示 :注入其他bean的属性

package com.hui.configfile.bean;

import org.springframework.stereotype.Component;

@Component
public class TestValue {
public String desc = "我是TestValue的属性:desc";
}

ConfigFileApplicationTests.java: 测试代码

package com.hui.configfile;

import com.hui.configfile.bean.TestValue;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.Resource;

import java.io.IOException;


@SpringBootTest
class ConfigFileApplicationTests {
// 读取配置属性
@Value("${person.name}")
private String name;

// 读取系统变量
@Value("#{systemEnvironment['os.name']}")
private String osName;

// 使用SpEL表达式(获取随机数)
@Value("#{T(java.lang.Math).random()}")
private double random;

// 注入其他bean的属性
@Autowired
private TestValue testValue;
@Value("#{testValue.desc}")
private String beanProperty;

// 注入文件资源
@Value("classpath:test.txt")
private Resource localFile;

// 注入网页资源
@Value("http://www.baidu.com")
private Resource urlWeb;

@Test
void run() throws IOException {
System.out.println("读取配置中的基本类型-->" + name);
System.out.println("读取系统变量-->" + osName);
System.out.println("使用SpEL表达式-->" + random);
System.out.println("注入其他bean的属性-->" + beanProperty);
// 读取文件
byte[] content = new byte[(int) localFile.contentLength()];
int read = localFile.getInputStream().read(content);
String fileContent = new String(content);
System.out.println("读取文件内容-->" + fileContent);

byte[] webContent = new byte[(int) urlWeb.contentLength()];
int read1 = urlWeb.getInputStream().read(webContent);
String webString = new String(webContent);
System.out.println("读取网页内容-->" + webString);
}
}

输出:

注入普通字符串-->哇哈哈哈哈哈
注入配置属性-->王麻子
注入系统变量-->null
使用SpEL表达式-->0.8653261032458481
注入其他bean的属性-->我是TestValue的属性:desc
注入文件资源-->JAVA,PHP,GO,C,PYTHON

注入网页资源--><!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

4.2 ${} #{}区别

@Value的值有两类:

  • ${ property : default_value }: 注入的是外部配置文件对应的property

  • #{ obj.property?:default_value }:注入的是SpEL表达式对应的内容,obj代表对象。default_value表示前面的值为空时的默认值。

5. @Value和@ConfigurationProperties区别

5.1 取值比较

@Value获取值和@ConfigurationProperties获取值比较

@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定(松散语法) 支持 不支持
SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持

5.2 使用场景

不管配置文件是application.yml还是application.properties,它们都能获取到配置中的值;

  • 当我们只是需要获取配置文件中的某项值时,建议使用: @Value;
  • 当我们专门编写了一个javaBean来和配置文件进行映射时,建议使用: @ConfigurationPropertie;