SpringBoot默认支持多种配置文件:

  • .XML 废弃,不推荐
  • .properties 推荐
  • .yml 极度推荐

注意:YAML目前还有一些不足,它无法通过@PropertySource注解来加载配置。但是,YAML加载属性到内存中保存的时候是有序的,所以当配置文件中的信息需要具备顺序含义时,YAML的配置方式比起properties配置文件更有优势。

动态配置支持

参数引用

application.properties中的各个参数之间,我们也可以直接通过使用PlaceHolder的方式来进行引用,就像下面的设置:

  1. book.name=SpringCloud
  2. book.author=ZhaiYongchao
  3. book.desc=${book.author} is writing${book.name}》

book.desc参数引用了上文中定义的book.namebook.author属性,最后该属性的值就是ZhaiYongchao is writing《SpringCloud》

使用随机数

在一些特殊情况下,有些参数我们希望它每次加载的时候不是一个固定的值,比如:密钥、服务端口等。在Spring Boot的属性配置文件中,我们可以通过使用${random}配置来产生随机的int值、long值或者string字符串,这样我们就可以容易的通过配置来属性的随机生成,而不是在程序中通过编码来实现这些逻辑。
${random}的配置方式主要有一下几种,读者可作为参考使用。

  1. # 随机字符串
  2. com.didispace.blog.value=${random.value}
  3. # 随机int
  4. com.didispace.blog.number=${random.int}
  5. # 随机long
  6. com.didispace.blog.bignumber=${random.long}
  7. # 10以内的随机数
  8. com.didispace.blog.test1=${random.int(10)}
  9. # 10-20的随机数
  10. com.didispace.blog.test2=${random.int[10,20]}

该配置方式可以用于设置应用端口等场景,避免在本地调试时出现端口冲突的麻烦

特定单位

时间 java.time.Duration

  • ns 十亿分之一秒
  • us 微秒
  • ms 毫秒
  • s
  • m 分钟
  • h 小时
  • d

    日期 java.time.Duration

  • y

  • m
  • w
  • d

    数据大小

  • B 字节

  • KB 千字节
  • MB 兆字节
  • GB 千兆字节
  • TB 太字节

    命令行参数

    在命令行方式启动Spring Boot应用时,连续的两个减号--就是对application.properties中的属性值进行赋值的标识。所以,java -jar xxx.jar --server.port=8888命令,等价于我们在application.properties中添加属性server.port=8888
    通过命令行来修改属性值是Spring Boot非常重要的一个特性,通过此特性,理论上已经使得我们应用的属性在启动前是可变的,所以其中端口号也好、数据库连接也好,都是可以在应用启动时发生改变,而不同于以往的Spring应用通过Maven的Profile在编译器进行不同环境的构建。其最大的区别就是,Spring Boot的这种方式,可以让应用程序的打包内容,贯穿开发、测试以及线上部署,而Maven不同Profile的方案每个环境所构建的包,其内容本质上是不同的。但是,如果每个参数都需要通过命令行来指定,这显然也不是一个好的方案,所以下面我们看看如果在Spring Boot中实现多环境的配置。

    多环境配置

    我们在开发任何应用的时候,通常同一套程序会被应用和安装到几个不同的环境,比如:开发、测试、生产等。其中每个环境的数据库地址、服务器端口等等配置都会不同,如果在为不同环境打包时都要频繁修改配置文件的话,那必将是个非常繁琐且容易发生错误的事。
    对于多环境的配置,各种项目构建工具或是框架的基本思路是一致的,通过配置多份不同环境的配置文件,再通过打包命令指定需要打包的内容之后进行区分打包,Spring Boot也不例外,或者说更加简单。
    在Spring Boot中多环境配置文件名需要满足application-{profile}.properties的格式,其中{profile}对应你的环境标识,比如:

  • application-dev.properties:开发环境

  • application-test.properties:测试环境
  • application-prod.properties:生产环境

至于哪个具体的配置文件会被加载,需要在application.properties文件中通过spring.profiles.active属性来设置,其值对应配置文件中的{profile}值。如:spring.profiles.active=test就会加载application-test.properties配置文件内容。
下面,以不同环境配置不同的服务端口为例,进行样例实验。

  • 针对各环境新建不同的配置文件application-dev.propertiesapplication-test.propertiesapplication-prod.properties
  • 在这三个文件均都设置不同的server.port属性,如:dev环境设置为1111,test环境设置为2222,prod环境设置为3333
  • application.properties中设置spring.profiles.active=dev,就是说默认以dev环境设置
  • 测试不同配置的加载
  • 执行java -jar xxx.jar,可以观察到服务端口被设置为1111,也就是默认的开发环境(dev)
  • 执行java -jar xxx.jar --spring.profiles.active=test,可以观察到服务端口被设置为2222,也就是测试环境的配置(test)
  • 执行java -jar xxx.jar --spring.profiles.active=prod,可以观察到服务端口被设置为3333,也就是生产环境的配置(prod)

按照上面的实验,可以如下总结多环境的配置思路:

  • application.properties中配置通用内容,并设置spring.profiles.active=dev,以开发环境为默认配置
  • application-{profile}.properties中配置各个环境不同的内容
  • 通过命令行方式去激活不同环境的配置

    默认加载路径

    SpringBoot 默认会加载这些路径加载核心配置文件,按优先级从高到低进行排列:具体规则详见 ConfigFileApplicationListener

    1. 工程根目录的config目录:file:./config/
    2. 工程根目录:file:./
    3. 类路径的config目录:classpath:/config/
    4. 类路径:classpath:/ (推荐使用)

如果存在多个配置文件,则严格按照优先级进行覆盖,最高者胜出:
举个简单的例子,例如再上述位置都有一个application.properties ,并且每个文件都写入了server.port=xx (xx分别是9001,9002,9003,9004),在启动成功之后,最终应用的端口为:9004。图例:
SpringBoot配置文件 - 图1
工程顶层目录
如果想修改默认的加载路径 或者 调改默认的配置文件名,我们可以借助命令行参数进行指定,例如:

  1. java -jar demo.jar --spring.config.name=app --spring.config.location=classpath:/myconfig/

注:不管 spring.config.location 配置什么值,默认总会按照 classpath:,classpath:/config,file:,file:config/ 的顺序进行搜索,优先级由低到高,也就是 file:config/ 获胜。如果你指定自己的位置,它们会优先于所有的默认位置,并使用相同的由低到高的优先级顺序。详见SpringBoot Custom-Config

加载顺序

Spring Boot为了能够更合理的重写各属性的值,使用了下面这种较为特别的属性加载顺序:

  1. 命令行中传入的参数。
  2. SPRING_APPLICATION_JSON中的属性。SPRING_APPLICATION_JSON是以JSON格式配置在系统环境变量中的内容。
  3. java:comp/env中的JNDI属性。
  4. Java的系统属性,可以通过System.getProperties()获得的内容。
  5. 操作系统的环境变量
  6. 通过random.*配置的随机属性
  7. 位于当前应用jar包之外,针对不同{profile}环境的配置文件内容,例如:application-{profile}.properties或是YAML定义的配置文件
  8. 位于当前应用jar包之内,针对不同{profile}环境的配置文件内容,例如:application-{profile}.properties或是YAML定义的配置文件
  9. 位于当前应用jar包之外的application.propertiesYAML配置内容
  10. 位于当前应用jar包之内的application.propertiesYAML配置内容
  11. @Configuration注解修改的类中,通过@PropertySource注解定义的属性
  12. 应用默认属性,使用SpringApplication.setDefaultProperties定义的内容

优先级按上面的顺序有高到低,数字越小优先级越高。
可以看到,其中第7项和第9项都是从应用jar包之外读取配置文件,所以,实现外部化配置的原理就是从此切入,为其指定外部配置文件的加载位置来取代jar包之内的配置内容。通过这样的实现,我们的工程在配置中就变的非常干净,我们只需要在本地放置开发需要的配置即可,而其他环境的配置就可以不用关心,由其对应环境的负责人去维护即可。