spring boot 源码解析(二)配置文件

上一篇笔记详细的说明的spring boot的一键启动及其原理。也说到了自动配置。
但是有些时候我们并不想要这个默认配置,所以这个默认配置是可以修改的。而spring boot使用一个全局的配置文件,配置文件名是固定的:

  • application.properties
  • application.yml

配置文件的作用:修改SpringBoot自动配置的默认值
SpringBoot在底层将所有的东西都给我配置好了,但是总有些我们不满意,所以就在配置文件里配置。properties我们经常见,所以不多说了。主要说说yml。

YML

全称:YAML (is not) a Markup Language (不)是一个标记语言
标记语言:xml是明显的标记语言。而yml可以理解为xml的简化版。yml是以数据为中心的。如下:
xml:


    1234

yml:

server:
  port: 1234
YML语法:
  1. 基本语法
    k: v 表示一对键值对(注意,冒号后面有个空格)
    以空格的缩进来控制层级关系。只要左对齐的一列数据,都是同一个层级的。
    属性和值也是大小写敏感的。
  2. 值的写法
    字面量(数字,字符串,布尔):k: v直接写就行。字符串默认不用加单引号或者双引号。不过双引号“”会转义字符串里面的特殊字符。也就是比如/n在双引号中输出会换行。单引号‘’不会转义特殊字符。也就是引起来的是什么就是什么。
    对象和Map(属性和值): k: v 在下一行来写对象的属性和值的关系。正常可以一个属性占一行。当然了也可以行内写法
    yml中对象(map)写法:
friends:
  name: zhang
  age: 20

yml中对象(map)行内写法:

friends: {name: zhang,age: 20} 

数组(List,Set):用-值表示数组中的元素。行内的话中括号包裹
数组的写法:

arr:
 - cat
 - dog
 - pig

数组的行内写法:

arr: [cat,dog,pig]
YML的使用

刚刚说了这么多YML的写法,但是归根结底我们还是要在实际中使用它。在实际中怎么做到把yml文件注入呢?
其实也是一个很简单的行为,首先需要与实体属性名称对应。其次这个实体需要两个注解修饰:

  • @Component(这个其实不仅是这个可以,只要把这个对象纳入spring管理就行)
  • @ConfigurationProperties(prefix = "xxx")(需要注意这个前缀就是要绑定的最底层的名称。)

下面用一个简单的demo来展示下这个是怎么使用的:

  1. 创建一个类:


    红色框起来的划重点,一会儿要考
  2. 将其属性想要绑定的写在yml文件上


    yml文件编写

    需要注意的是这个不用全部属性。比如其中某个属性没有值不写就行了。

  3. 其实到这就已经绑定上了,但是为了确认结果所以我们实际使用下:


    注入并返回
  4. 返回的就是我们预测到的内容。说明我们绑定成功了。


    确定绑定成功了!

ps:注意下之前我们说过yml文件中大小写敏感。而且其驼峰法和-是可以互换的。比如 user-name 是等价于userName的。
到此简单的使用就完成了,其实properties也和这个用法差不多的。简单说一下properties的用法:
前面的类不用动,properties的写法:

demo1

然后我们访问的结果如我们所想:
结果

@Value和@ConfigurationProperties区别
@Value和@ConfigurationProperties区别

其实简单的看下二者的区别就能知道在二者中如何选取:

  • 如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某个值,就使用@Value。
  • 如果说,我们专门编写了一个javaBean来和配置文件进行映射,那么我们直接使用@ConfigurationProperties

说到配置文件绑定,不得不提另外一个注解:
@PropertySource(value = {classpath:xxx.properties})
这个注解的用处是指定配置文件名称去找配置文件(不指定会默认去application全局配置文件找)
还有一个:
@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效
Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件也不能自动识别。想让Spring的配置文件生效,加载进来要在启动类上加上注解:
@ImportResource(locations={"claseepath:beans.xml"})
当然了这个用法本身就有问题,spring到spring boot进化到不用写繁杂的xml了,在这我们再写xml引入回去?这不就跟老祖宗用了几百上千年好不容易简化文字了,然后现在各种用繁体的脑回路一样了么?所以说对于spring boot中想使用spring 配置文件,我们换一种用法:
直接在spring boot的配置类中注入bean。如下使用方法:

注入bean

配置文件中的表达式

  1. 可以使用随机数:${random.XXXX}
  2. 可以用${xxx}获取之前值的表达式。

Profile

关于这个Profile文件,其实是特别方便的一个实用性很强的工具。大概意思是我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml。
默认使用的是application.properties的配置。但是我们可以选择激活指定的profile文件。
如下demo中,三个配置文件,默认使用的是application.properties


启动端口是1234

仍然是这个三个配置文件,但是在全局配置文件中激活不同的版本号后,会启动不同的配置文件:


启动dev的配置文件

当然了,好几个文件来回切换也许有人会觉得麻烦(反正我不觉得,反而比yml的多文档块好用),所以yml有一种实现叫做多文档块。就是用三个-分割。每一个块取一个文件名称。然后最上面指定使用哪个块的配置。也简单的很,下面是使用demo:
yml多文档块

其实这个yml和properties是差不多的。目前看起来似乎是yml更加方便,毕竟只有一个文件简单明了。
但是大家想一个现实问题:正常我们一个项目,redis,mysql,甚至有的还用别的中间件。然后还有很多配置:默认下载路径啊,图片上传路径啊,最大线程数等等,这样一个配置好几十行。用多文档块的形式我个人是觉得很容易混淆。不过这个是我个人看法,具体还是要看大家习惯用哪个。

除了配置文件中指定版本,其实也可以在运行jar的时候命令行指定版本。如下:


prod启动

如图,明明配置文件中激活的是dev版本的配置,但是我在启动jar的时候指定要用prod版本配置。结果是命令行的命令赢了,最终用prod配置启动的。

配置文件优先级

按照正常的习惯,我们一般配置文件都在resources下面,但是其实配置文件不仅仅可以在这个下面。
事实上配置文件可以在四个位置:

  1. 项目根目录的config文件下
  2. 项目根目录下
  3. 项目resources的config文件下
  4. 项目resources下
    上面四个的优先级是从高到低的,下面我们一个个测试一下:


    配置文件优先级classpath:config>classpath

    如图两个位置的配置文件,最终实现了的是config文件下的。


    项目根目录的配置文件优先级高于类目录下的

    项目根目录config文件夹下面的优先级最高

注意下,这个高优先级的配置会覆盖低优先级的配置。这个要注意,A,B,C,D四个配置文件,不是说只读优先级最高的那个。而是每个都会读取。只不过如果有相同的配置,会以最高优先级的为主。其实这四个文件可以形成互补配置!

另外注意当项目打好包以后,在运行jar的时候,是可以用命令行参数的形式指定配置文件的位置(--spring.config.location=文件全路径名)。而指定配置文件和默认加载的这些配置文件会共同起作用形成互补配置。
需要注意的是:命令行指定的配置文件,是最高级的!

外部配置加载顺序

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

  1. 命令行参数
  2. 来自java:comp/env的NDI属性
  3. java系统属性
  4. 操作系统环境变量
  5. jar包外部的application-{profile}.properties/yml
  6. jar包内部的application-{profile}.properties/yml
    ...
    实际上官方文档中有17中配置方法。但是太多了就不一一说明了,用到的时候可以自己去查看官方文档。

Spring Boot自动配置原理

配置文件到底能写什么?怎么写?
这个官方文档列出来能配置的属性,但是这个其实特别长。主要弄懂自动配置原理,就能知道怎么用了。

自动配置原理(这个其实上一章就介绍了,在讲启动类的时候):
  1. SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration
  2. @EnableAutoConfiguration作用:有个SpringFactoriesLoader类,这个类会获取项目类路径下META-INF/spring.factories中的所有properties文件对应的配置类类名添加到容器中。
    总结起来一句话:将类路径下MATE-INF/spring.factories里面的所有配置类纳入容器中。
  3. 每一个自动配置类进行自动配置功能。
  4. 每个配置类上都有个注解,其中绑定的就是我们配置文件中的属性名称。*
  5. 所有在配置文件中能够配置的属性都是在XXXproperties类种中封装的。配置文件能配置什么可以参照某个功能对应的这个属性类。
  6. 根据不用的条件判断,会决定这个类是否会生效,一旦这个配置类生效了,在只有一个有参构造器的情况下,参数的只会从容器中拿,并且会给容器中添加一个组件。这个组件中的值就是从properties中获取的。

所以总结一下:我们能配置的属性,都是来源于这个功能的properties类
精髓

  • SpringBoot启动会加载大量的自动配置类
  • 我们看我们需要的功能有没有SpringBoot默认写好的自动配置类。
  • 我们在看这个自动配置类中到底配置了哪些组件,如果我们要的组件springBoot中有,我们就不需要额外配置了
  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们可以在配置文件中指定这些属性的值。

SpringBoot中:
XXXAutoConfiguration:自动配置类,给容器中添加组件
XXXProperties:封装配置文件中相关属性

@Conditional及其派生注解:
@Conditional是判断是否满足某条件,满足则生效。

Conditional扩展注解

自动配置类一定在满足一定的条件才生效。
这个也就是我们启动springBoot,虽然加载了很多自动配置,但是很多是不满足注解条件,所以不生效的。
怎么知道哪些配置生效了,哪些没生效呢?
可以在配置中配置debug=true。
这样启动项目的时候会有自动配置报告:输出所有启动了的配置。也会输出没有启动的配置。

至此,这个springboot中的关于配置的讲解到此结束,如果稍微帮到你了记得点个喜欢点个关注。也祝大家工作顺顺利利!

你可能感兴趣的:(spring boot 源码解析(二)配置文件)