SpringBoot配置文件.yaml(.yml)和.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 这是一个递归写法 ;

  1. YAML A Markup Language:是一个标记语言
  2. 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格式配置文件:

image

properties格式配置文件:

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 配置文件)

image

properties配置文件在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
image

2、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;
​ 可以直接在测试的时候,配置传入命令行参数 ,打包好的项目运行的时候指定我们的环境:

image

​ 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配置文件支持列表,如下所示:

image

当然,从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)]

image

此外,如果你在相同优先级位置同时有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("********************************************************");    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335