SpringBoot配置文件.yaml和.properties
很多优秀的框架都有自己的配置文件, 比如hibernate有hbm,mybatis 有properties配置文件。
Springboot使用一个全局的配置文件,而且配置文件的名字是固定的。 有两种
- application.properties
- application.yml
springboot 配置文件的作用是用来 修改SpringBoot自动配置的默认值;SpringBoot在底层都给我们自动配置好; 像我们Tomcat 启动 默认配置端口是8080 . 如果要修改, 我们就在这两个文件的一种中来修改,
-
YML (也叫YAML : YAM Ain't Markup Language)**
YAML Ain't Markup Language 这是一个递归写法 ;
- YAML A Markup Language:是一个标记语言
- YAML isn't Markup Language:不是一个标记语言;
标记语言: 我们以前用的配置文件,大多都使用 xxxx.xml 文件 ;
YAML : 是一种以数据为中心的配置文件, 比json,xml 等更适合做配置文件
举个栗子:
以 修改端口为例 :
yml :
server:
port: 8081
xml :
<server>
<port>8081</port>
</server>
xml 配置 将太多的浪费在了标签上面。
yml 基本语法:
k:(空格)v:表示一对键值对(空格必须有);
以 空格 的缩进来控制层级关系;只要是左对齐的一列数据,都是同一个层级的
server:
port: 8081
path: /hello
属性和值也是大小写敏感;
值的写法:
-
字面量:普通的值(数字,字符串,布尔)
k: v:字面直接来写;
字符串默认不用加上单引号或者双引号;
"":双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思
name: "zhangsan \n lisi":输出;zhangsan 换行 lisi
'':单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
-
对象、Map(属性和值)(键值对):
k: v:在下一行来写对象的属性和值的关系;注意缩进
对象还是k: v的方式
friends:
lastName: zhangsan
age: 20
行内写法:
friends: {lastName: zhangsan,age: 18}
-
配置文件注入
javaBean :
image可以导入配置文件处理器依赖,以后编写配置就会有代码提示;
image.png代码展示配置文件注入属性值 :
package com.example.webservice.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
*
* ConfigurationProperties(prefix ="person") 将本类中的所有属性和配置文件中的相关配置进行绑定
* prefix ="person 表示对哪个文件进行绑定
* Component 表示这是一个容器, 只有在容器中 ConfigurationProperties 才能使用
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private boolean man;
private Date birth;
private Map<String,Object>map;
private List<Object>list ;
private Son son ;
.....省略get/set 以及toString 方法
}
package com.example.webservice.bean;
public class Son {
private String name;
private Integer age ;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Son{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
properties文件绑定的写法
person.name=爸爸
person.age=45
person.man=true
person.birth=2019/8/8
person.map.k1=h1
person.map.k2=h2
person.list=a,1,son
person.son.name=儿子
person.son,age=20
yml 文件绑定的写法:
person:
name: 爸爸
age: 25
birth: 2018/2/8
man: true
list:
- a
- 2
- son
map: {key1:value1,key2:value2}
son:
name: 儿子
age: 5
测试类 : 在我们的test 文件夹下 :
package com.example.webservice;
import com.example.webservice.bean.Person;
import org.junit.Test;import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class WebserviceApplicationTests {
@Autowired
Person person;
@Test
public void contextLoads() {
// 直接运行这个方法 ,而不是运行整个程序
System.out.println(person);
System.out.println("********************************************************");
}
}
1、什么是yml什么是properties?
对于刚接触springboot的同学,肯定存在一时搞不清楚yml和properties配置文件有什么区别。首先,无论是yml还是properties,都是SpringBoot配置文件中的一种格式,默认名为application.yml或application.properties ,默认放在resources文件夹下,当然,放在resources/config文件夹下也是可以读取到的。
2、各自的优点?
下面我们以配置redis缓存数据库的配置文件为例子进行说明:
yml格式配置文件:
imageproperties格式配置文件:
image可以看到,yml格式的配置文件有着可读性更强的树型结构,也更加简洁,但对于新手而言,properties格式的配置文件也是不错的选择,易于理解,总之,两种格式的配置文件殊途同归,springboot项目都可以识别。
3、yml格式配置文件写法和坑点
对于properties格式的配置文件,我无需多言,所有学习springboot的同学最开始接触的还是properties格式的配置文件。那么properties格式配置文件如何转yml格式呢?
(1)不同等级用冒号隔开,次等级前用空格,不能用制表符tab,如spring.redis.host=127.0.0.1配置文件中,spring作为第一级,redis作为第二级.
(2)如果冒号后是值,则用一个空格将冒号和值隔开。
(3)坑点:yml格式中一定不要用制表符tab,冒号和值之间一定要有空格。
4、总结
两种配置文件在 springboot中都可以识别,用其中一种就可以。如果一个目录下存在两种格式的配置文件,则先读取properties格式的配置文件,后读取yml格式的配置文件。读取到的配置以第一次的为准。
控制台打印结果 (使用的 yml 配置文件)
imageproperties配置文件在idea中默认utf-8可能会乱码 。因为spring properties 默认是ASCII 码 ,所以需要将properties 默认编码改为UTP-8 ,再√上旁边的 将其运行时转换为ASCII码;再输入中文就好了
image都改成utf-8 ,再输入中文就好了。
-
@Value获取值和@ConfigurationProperties获取值比较**
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
配置文件yml还是properties他们都能获取到值;
如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
-
配置文件注入值数据校验
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
/**
* <bean class="Person">
* <property name="name" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
* <bean/>
*/
//name必须是邮箱格式
@Email
//@Value("${person.name}")
private String name;
//@Value("#{11*2}")
private Integer age;
//@Value("true")
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
。。。。。get/set /toString
@PropertySource&@ImportResource&@Bean
@PropertySource:加载指定的配置文件;
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
* @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
* prefix = "person":配置文件中哪个下面的所有属性进行一一映射
*
* 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能;
* @ConfigurationProperties(prefix = "person")默认从全局配置文件中获取值;
*
*/
@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
//@Validated
public class Person {
/**
* <bean class="Person">
* <property name="name" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
* <bean/>
*/
//name必须是邮箱格式
// @Email
//@Value("${person.name}")
private String name;
//@Value("#{11*2}")
private Integer age;
//@Value("true")
private Boolean boss;
@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;
Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;
想让Spring的配置文件生效,加载进来;就要将 @ImportResource 标注在一个配置类上
@ImportResource(locations = {"classpath:beans.xml"})//类路径上添加配置类的路径
导入Spring的配置文件让其生效
不来编写Spring的配置文件 ,下面这就是我们通常的Spring配置类文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloService" class="com.example.webservice.controller.Hello"></bean>
</beans>
SpringBoot推荐给容器中添加组件的方式;推荐使用全注解的方式
1、配置类@Configuration------>Spring配置文件
2、使用@Bean给容器中添加组件
/**
* @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件
*
* 在配置文件中用<bean><bean/>标签添加组件
*
*/
@Configuration
public class MyAppConfig {
//将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
@Bean
public HelloService helloService02(){
System.out.println("配置类@Bean给容器中添加组件了...");
return new HelloService();
}
}
配位文件占位符
1、随机数
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
2、占位符获取之前配置的值,如果没有可以是用:指定默认值
properties
person.name=张三${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
// 如果没有hello这个属性, 则会直接输出 ${person.hello} , 如果加了 ${person.hello:hello}_dog 则会直接赋值 输出
hello_dog
person.dog.name=${person.hello:hello}_dog
person.dog.age=15
3、Profile
1、多Profile文件
我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml
springboot默认使用配置文件为application.properties;
所以我们在然后在application.properties配置文件中 激活自定义的环境配置文件就可以了从application.properties 加载到application-dev.properties 文件了
在配置文件中指定 spring.profiles.active=dev
image image2、yml支持多文档块方式
server:
port: 8081
spring:
profiles:
active: prod 表示当前激活使用哪个环境 --- 表示环境的分割 ,分成不同的文档块。
---
server:
port: 8083
spring:
profiles: dev
---
server:
port: 8084
spring:
profiles: prod #指定属于哪个环境
4、激活指定profile
1、在配置文件中指定 spring.profiles.active=dev
2、命令行:
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;
可以直接在测试的时候,配置传入命令行参数 ,打包好的项目运行的时候指定我们的环境:
3、虚拟机参数; 在运行的时候 选择Editor configrations
image image-Dspring.profiles.active=dev
5、配置文件加载位置
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
–file:./config/ 文件路径config目录--->最高优先级
–file:./ 文件路径根目录--->其次
–classpath:/config/ 类路径config目录--->再其次
–classpath:/ 类路径根目录--->最低优先级
优先级由高到底,高优先级的配置会覆盖低优先级的配置;
SpringBoot会从这四个位置全部加载主配置文件:互补配置;
我们还可以通过spring.config.location来改变默认的配置文件位置
项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;
进入命令行 :
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties(properties的硬盘文件目录)
6、外部配置加载顺序
SpringBoot也可以从以下位置加载配置; 优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置
1.命令行参数
所有的配置都可以在命令行上进行指定
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
多个配置用空格分开; --配置项=值
2.来自java:comp/env的JNDI属性
3.Java系统属性(System.getProperties())
4.操作系统环境变量
5.RandomValuePropertySource配置的random.*属性值
由jar包外向jar包内进行寻找;
优先加载带profile
7.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
8.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
再来加载不带profile
9.jar包外部的application.properties或application.yml(不带spring.profile)配置文件
10.jar包内部的application.properties或application.yml(不带spring.profile)配置文件
11.@Configuration注解类上的@PropertySource
12.通过SpringApplication.setDefaultProperties指定的默认属性
所有支持的配置加载来源;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2.yml文件
name: hha
age: 60
friend:
- good
- easy
- bug
params:
addr: ZZ
code: EE
name: 洗洗
3.实体类
package com.my.last;
import java.util.List;
import java.util.Map;
public class Student { private String name;
private int age;
private List<String> friend ;
private Map<String, Object> params; /**
* @return the name */ public String getName() {
return name; }
/**
* @param name the name to set */ public void setName(String name) { this.name = name; }
/**
* @return the age */ public int getAge() { return age; }
/**
* @param age the age to set */ public void setAge(int age) { this.age = age; }
/**
* @return the friend */ public List<String> getFriend() { return friend; }
/**
* @param friend the friend to set */ public void setFriend(List<String> friend) { this.friend = friend; }
/**
* @return the params */ public Map<String, Object> getParams() { return params; }
/**
* @param params the params to set */ public void setParams(Map<String, Object> params) { this.params = params; }
/* (non-Javadoc)
* @see java.lang.Object#toString() */ @Override
public String toString() { return "Student [name=" + name + ", age=" + age + ", friend=" + friend + ", params=" + params + "]"; } }
4.测试类
package com.my.last;
import org.yaml.snakeyaml.Yaml;
public class Test { public static void main(String[] args) {
Yaml yaml = new Yaml();
Student student = yaml.loadAs(Test.class.getResourceAsStream("/test.yml"), Student.class);
System.out.println(student); }
}
** 或者依赖**
<dependency>
<groupId>org.jyaml</groupId>
<artifactId>jyaml</artifactId>
<version>1.3</version>
</dependency>
解析方法:
Student student2 = null; try {
student2 = org.ho.yaml.Yaml.loadType(Test.class.getResourceAsStream("/test.yml"), Student.class);
} catch (FileNotFoundException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(student2);</pre>
二者区别
在于其拥有天然的树状结构,所以着手尝试将properties文件更改为yml文件,发现了几个要注意的地方:
1、在properties文件中是以”.”进行分割的, 在yml中是用”:”进行分割;
2、yml的数据格式和json的格式很像,都是K-V格式,并且通过”:”进行赋值;
3、在yml中缩进一定不能使用TAB,否则会报很奇怪的错误;(缩进特么只能用空格!!!!)
4、yml每个k的冒号后面一定都要加一个空格;
5、使用spring cloud的maven进行构造的项目,在把properties换成yml后,一定要进行mvn clean insatll
6、yml是跨语言的:可以在包括JAVA,go,python等大量的语言中使用,比如做云计算使用go和java的时候,可以通过配置中心使用同一份配置!
7、支持列表:区别于properties只支持键值对数据,yml配置文件支持列表,如下所示:
当然,从properties转yml文件会遇到很多坑,在此记录下:
1,层级关系缩进不能用tab键:每次都数2.4.6这样打空格。。。
2,每个key的后面需要加:,每个:后面还需要加一个空格!
3,列表的短横线后面需要有个空格。
两个关键点:
第一个是yml是支持中文内容的,properties想使用中文只能用unicode编码
第二个是顺序问题,properties是不保证加载顺序的,yml有先后顺序,实际用例比如springcloud的zuul网关路由配置,如果一个uri同时满足两个匹配规则,properties你是不知道它到底使用了哪个规则的,而yml则一定是使用了靠后的那个路由规则
Java 的 Properties 加载属性文件后是无法保证输出的顺序与文件中一致的,因为 Properties 是继承自 Hashtable , key/value 都是直接存在 Hashtable 中的,而 Hashtable 是不保证进出顺序的。
总有时候会有关心顺序一致的需求,恰如有 org.apache.commons.collections.OrderdMap(其实用 LinkedHashMap 就是保证顺序) 一样,我们也想要有个 OrderdProperties。
详见: https://blog.csdn.net/qq1169091731/article/details/53012071
Spring Boot中application.properties和application.yml加载顺序
使用@PropertySource注解加载自定义配置文件,该注解无法加载yml配置文件。使用@Value注解获得文件中的参数值
application.properties和application.yml文件可以放在一下四个位置:
- 外置,在相对于应用程序运行目录的/congfig子目录里。
- 外置,在应用程序运行的目录里
- 内置,在config包内
- 内置,在Classpath根目录
同样,这个列表按照优先级排序,也就是说,src/main/resources/config下application.properties覆盖src/main/resources下application.properties中相同的属性,如图:
[图片上传失败...(image-9f4435-1604553023059)]
此外,如果你在相同优先级位置同时有application.properties和application.yml,那么application.properties里面的属性就会覆盖里application.yml的属性
package com.example.webservice.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
*
* ConfigurationProperties(prefix ="person") 将本类中的所有属性和配置文件中的相关配置进行绑定
* prefix ="person 表示对哪个文件进行绑定
* Component 表示这是一个容器, 只有在容器中 ConfigurationProperties 才能使用
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private boolean man;
private Date birth;
private Map<String,Object>map;
private List<Object>list ;
private Son son ;
.....省略get/set 以及toString 方法
}
package com.example.webservice.bean;
public class Son {
private String name;
private Integer age ;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Son{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
properties文件绑定的写法
#注释方法 Ctrl + /
person.name=爸爸
person.age=45
person.man=true
person.birth=2019/8/8
person.map.k1=h1
person.map.k2=h2
person.list=a,1,son
person.son.name=儿子
person.son,age=20
yml 文件绑定的写法:
person:
name: 爸爸
age: 25
birth: 2018/2/8
man: true
list:
- a
- 2
- son
map: {key1:value1,key2:value2}
son:
name: 儿子
age: 5测试类 : 在我们的test 文件夹下 :package com.example.webservice;import com.example.webservice.bean.Person;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)@SpringBootTestpublic class WebserviceApplicationTests { @Autowired Person person; @Test public void contextLoads() { // 直接运行这个方法 ,而不是运行整个程序 System.out.println(person); System.out.println("********************************************************"); }