SpringBoot教程(三)(配置文件解析)_下

      配置文件解析(下)

                                                                                                 原创者:文思

一、yml(YAML Ain’t Markup Language)基本用法

application.properties或application.yml

配置文件的作用:修改springboot的默认配置。

YAML:以数据为中心,比json,xml等更适合做配置文件

基本语法:

K:(空格)V :表示一对键值对。以空格的缩进来控制层级关系,只要是左对齐的一列数据,都是一个层级的。

值的写法:

字面量:普通的值(数据、字符串、布尔),k: v形式直接来写。如果有特殊字符,不需要转义可用双引号,需要转义可用单引号。

对象、Map:k: v形式直接来写,在下一行写对象的属性和值,注意缩进。

还可以使用行内写法:friends:{name:zhangsan,age: 18}

数组(List、Set):用- 值表示数组中的一个元素

示例:

新建一个yml配置文件:

server:

     port: 8081

person:

     lastName: zhangsan

     age: 18

     boss:  false

     birth:  2018/7/17

 map:  {t1:test1,t2:test2,t3:test3}

 map2:

   t1:  test11

   t2:  test22

   t3:  test33

list:

   -  lisi

   -  wangwu

   -  zhaoliu

 dog:

    name:  小狗

    age:  2

创建对应的对象:

@Component//声明为spring组件,让spring容器管理

@ConfigurationProperties(prefix="person")//默认从全局配置文件中获取值,告诉springboot将此类的属性与配置文件的配置绑定

public classPerson {

    private String lastName;

    private Integer age;

    private Boolean boss;

    private Date birth;

    privateMap map;

    privateMap map2;

    private List list;

    private Dog dog;

    public String toString(){

       return "Person{"+

              "lastName="+ lastName+

              ",age="+ age+

              ",boss="+ boss+

              ",birth="+ birth+

              ",map="+ map+

              ",map2="+ map2+

              ",list="+ list+

              ",dog="+ dog+

              "}";

    }

 .....setter\getter方法略

}

package com.wensi.springbootdemo1.yml;

public classDog {

    private String name;

    private Integer age;

    public String getName() {

       return name;

    }

 .....setter\getter方法略

}

运行测试类:

package com.wensi.springbootdemo1;

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;

import com.wensi.springbootdemo1.yml.Person;

@RunWith(SpringRunner.class)

@SpringBootTest

public classAppTest{

    @Autowired

    Personperson;

    @Test

    public void contextLoads(){

       System.out.println(person);

    }

}

运行结果:

Person{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST 2018,map={t1=test1, t2=test2, t3=test3},map2={t1=test11,t2=test22, t3=test33},list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@796d3c9f}

使用properties格式的配置文件application.properties:

person.lastName=zhangsan

person.age=18

person.boss=false

person.birth=2018/7/17

person.map.t1=test1

person.map.t2=test2

person.map.t3=test3

person.list=lisi,wangwu,zhaoliu

person.dog.name=小狗

person.dog.age=2

运行测试类的结果:

Person{lastName=zhangsan,age=18,boss=false,birth=TueJul 17 00:00:00 CST 2018,map={t3=test3, t2=test2,t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@6f8d7714}

使用@value:

@Component

public class PersonValue {

    @Value("${person.lastName}")

    private String lastName;

    @Value("#{2*11}")

    private Integer age;

    @Value("true")

    privateBooleanboss;

运行结果:

Person{lastName=zhangsan,age=22,boss=true,birth=null,map=null,map2=null,list=null,dog=null}

@value和@ConfigurationProperties区别:

例如:

@Component

@ConfigurationProperties(prefix="person")

@Validated

public class Person {

    @Email

    private String lastName;//lastName必须是邮箱格式

    private Integer age;

    private Boolean boss;

    private Date birth;

运行结果:

Binding to targetPerson{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST2018,map={t3=test3, t2=test2, t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@7689ddef} failed:

    Property:person.lastName

    Value:zhangsan

    Reason: 不是一个合法的电子邮件地址

使用@value时:

@Component

@Validated

public class PersonValue {

    @Email

    @Value("${person.lastName}")

    private String lastName;

运行结果:

Person{lastName=zhangsan,age=22,boss=true,birth=null,map=null,map2=null,list=null,dog=null}。说明@value不支持数据校验

对于复杂数据类型:

@Component

public class PersonValue {

    @Value("${person.lastName}")

    private String lastName;

    @Value("#{2*11}")

    private Integer age;

    @Value("true")

    private Boolean boss;

    private Date birth;

    @Value("${person.map}")

    private Map map;

运行结果:

Caused by: java.lang.IllegalArgumentException:Could not resolve placeholder 'person.map' in value "${person.map}"

说明@value不支持复杂数据类型,如map。

使用建议:

如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value。

如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties

@PropertySource和@importResource

根据名称分析@PropertySource可加载非默认的配置文件,即加载指定的配置文件,当我们想将一些特定业务所需要的配置与系统默认配置分开维护时,需要@PropertySource

@Component

@ConfigurationProperties(prefix="person")

@PropertySource(value={"classpath:person.properties"})

public class PersonPropertySource {

    private String lastName;

    privateInteger age;

运行结果:

Person{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST 2018,map={t3=test3, t2=test2,

t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@1b32cd16}


@importResource导入spring的配置文件,让配置文件里面的内容生效

因为springboot里面没有spring的配置文件,自己编写地配置文件也不能识别,所以需要使用@importResource加载进来。示例:

public class TestImportService {

}

bean.xml:

@SpringBootApplication

@ImportResource(locations = {"classpath:bean.xml"})

public class App

{

……

}

测试用例:

@Autowired

    ApplicationContext ioc;

    @Test

    public void testImportSource(){

       System.out.println(ioc.containsBean("testImportService"));

    }

运行结果:true

SpringBoot推荐给容器中添加组件的方式:推荐使用全注解的方式

1、配置类@Configuration------>Spring配置文件

2、使用@Bean给容器中添加组件,配置类这里使用@Bean注解

/**

* @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件

** 在配置文件中用标签添加组件

*/

@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、占位符获取之前配置的值,如果没有可以是用:指定默认值

person.last‐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

person.dog.age=15

person.dog.name=${person.hello:hello}_dog 

如果${person.hello: hello}取不到值就默认值hello


多profile文件

应该对开发\测试\生产环境下切换

文件名可以是application-{profile}.properties/yml

默认使用的是application.properties/yml

激活指定profile

在配置文件中指定spring.profile.activie=dev,示例,新建application-dev.properties:

application.properties中增加spring.profile.activie=dev

Yml格式的多profile:yml支持文档块模式

spring:

  profiles:

    active: prod

---

server:

  port: 8083

spring:

  profiles: prod

---

server:

  port: 8084

spring:

  profiles:dev

运行如图:

spring.profiles.active是激活使用指定的配置文件。

另一种可以使用命令行的方式:java -jar ***.jar –spring.profiles.active=dev

还有一种虚拟机参数:-Dspring.profiles.active=dev


配置文件加载位置

Spring

boot启动会扫描以下位置的application.properties或yml作为spring

boot的默认配置文件

-file:./config/

-file:./

-classpath:/config/

-classpath:/

以上是按照优先级从高到低的顺序,所有位置的文件都会被加载,高优先级配置内容会覆盖低优先级配置内容。


外部配置加载顺序

SpringBoot也可以从外部以下位置加载配置; 优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置

1.命令行参数

所有的配置都可以在命令行上进行指定

java -jarspring-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

6.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件

7.jar包内部的application-{profile}.properties或application.yml(spring.profile)配置文件再来加载不带profile

8.jar包外部的application.properties或application.yml(不spring.profile)配置文件

9.jar包内部的application.properties或application.yml(不spring.profile)配置文件

10.@Configuration注解类上的@PropertySource

11.通过SpringApplication.setDefaultProperties指定的默认属性

示例:

java

-jar springbootdemo1-0.0.1-SNAPSHOT.jar -server.port=8088,

启动端口就覆盖配置文件的里的端口设置了,启动端口为8088

二、自动配置原理

配置文件能配置的属性参照:

https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/htmlsingle/#common-application-properties

观察@ SpringBootApplication源码

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan(excludeFilters = {

       @Filter(type = FilterType.CUSTOM, classes =

TypeExcludeFilter.class),

       @Filter(type = FilterType.CUSTOM, classes =

AutoConfigurationExcludeFilter.class) })

public @interface SpringBootApplication

1)SpringBoot启动时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration

2) @EnableAutoConfiguration利用EnableAutoConfigurationImportSelector选择器给容器导入META-INF/Spring.factories中的默认配置对应的组件。(可查看selectImports()方法-->

List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置-->

SpringFactoriesLoader.loadFactoryNames()//扫描所有jar包类路径下META‐INF/spring.factories把扫描到的这些文件的内容包装成properties对象从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中)

3)如上每一个自动配置类进行自动配置

4) 以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;

@Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件

@EnableConfigurationProperties(HttpEncodingProperties.class)

//启动指定类的

ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把

HttpEncodingProperties加入到ioc容器中

@ConditionalOnWebApplication

//Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果

满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效

@ConditionalOnClass(CharacterEncodingFilter.class)

//判断当前项目有没有这个类

CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;

@ConditionalOnProperty(prefix= "spring.http.encoding", value = "enabled", matchIfMissing=

true) //判断配置文件中是否存在某个配置spring.http.encoding.enabled;如果不存在,判断也是成立的

//即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;

public class HttpEncodingAutoConfiguration{

//他已经和SpringBoot的配置文件映射了

private final HttpEncodingPropertiesproperties;

//只有一个有参构造器的情况下,参数的值就会从容器中拿

publicHttpEncodingAutoConfiguration(HttpEncodingProperties properties) {

this.properties =properties;

}

@Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取

@ConditionalOnMissingBean(CharacterEncodingFilter.class)

//判断容器没有这个组件?

publicCharacterEncodingFilter characterEncodingFilter() {

CharacterEncodingFilter filter = newOrderedCharacterEncodingFilter();

filter.setEncoding(this.properties.getCharset().name());

filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));

filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));

return filter;

}

根据当前不同的条件判断,决定这个配置类是否生效?

一但这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的

这里能看出配置文件能配置的属性都是来源于HttpEncodingProperties类。

精髓:

1:spring boot启动会加载大量的自动配置类

2:我们看我们需要的功能有没有springboot默写好的自动配置类

3:我们看这个自动配置类中配置了哪些组件(我们要用的有就不用再配置了)

4:给容器中自动配置类添加组件时,会从properties类中获取某些属性,我们可以在配置文件中指定这些属性的值

xxxAutoConfigurartion自动配置类,给容器中添加组件,xxxAutoConfigurartion下的xxxxProperties:封装配置文件中相关属性;

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • SpringMVC原理分析 Spring Boot学习 5、Hello World探究 1、POM文件 1、父项目...
    jack_jerry阅读 1,256评论 0 1
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,222评论 1 92
  • Scala与Java的关系 Scala与Java的关系是非常紧密的!! 因为Scala是基于Java虚拟机,也就是...
    灯火gg阅读 3,399评论 1 24
  • 第一章 劫机 美国洛杉矶唐人街的一家餐厅中一名穿着白色大褂的带着浅红色墨镜的男子一个人吃着炒面。整个餐厅除了餐厅的...
    作者酒肉和尚阅读 343评论 0 0