Spring Boot允许外化(externalize)你的配置,这样你能够在不同的环境下使用相同的代码。

你可以使用properties文件,YAML文件,环境变量和命令行参数来外化配置。使用@Value注解,可以直接将属性值注入到你的beans中,并通过Spring的Environment抽象或绑定到结构化对象来访问。


1.springboot项目内读取配置文件的属性值

springboot 默认读取src\main\resources\application.properties;

例如:

我们在配置文件中准备了2个配置字段,如下:

com.zjt.welcomeWords01="你好,我是com.zjt.welcomeWords01"
com.zjt.welcomeWords02="你好,我是com.zjt.welcomeWords02"

我想要在controller中读取到这连个配置文件的值,并通过rest返回到前台,我们可以直接在controller中定义变量,

并在变量上声明一个这样的注解:  @Value(value="${com.zjt.welcomeWords01}"),便可获取到配置文件中的值。

如:这样编写controller:

@RestController
public class Controller01 { @Value(value="${com.zjt.welcomeWords01}")
private String word01;
@Value(value="${com.zjt.welcomeWords02}")
private String word02; @ResponseBody
@RequestMapping("test01")
public String test01(){
System.out.println("word01:"+word01);
return "word01:"+word01;
} @ResponseBody
@RequestMapping(value = "test02", produces = "application/json; charset=UTF-8")
public String test02(){
System.out.println("word02:"+word02);
return "word02:"+word02;
}
}

访问:http://localhost:8080/test01

访问:http://localhost:8080/test02

注意,如果你用的也是IDEA的话,在springboot读取配置文件的环节,可能会使用Unicode读取,造成乱码;所以,要配置一下IDEA字符集:

这里需要额外说一下:我们在使用springboot的@RestController注解时,如果不对@RequestMapping的produces属性进行定义,则默认会返回text/html的Content-Type;

如果你的项目环境接口调试时要求必须是application/json的Content-Type,你可以像我上面的controller中写的那样定义produces属性;

上面说的是在字段中通过@value注解来获取配置文件的值,当你的配置文件中有n个互相关联的属性需要读取的时候,我们可以使用配置文件实体bean的方式将配置文件的相关值加载到bean中,再通过bean的属性来获取值:

我们由此,先新建配置bean,注意使用@ConfigurationProperties(prefix = "com.zjt"),来指定配置文件字段的前缀,bean的字段名要与配置文件属性名称完全一致:

@ConfigurationProperties(prefix = "com.zjt")
public class ConfigBean01 {
private String word01;
private String word02; public String getWord01() {
return word01;
}
public void setWord01(String word01) {
this.word01 = word01;
}
public String getWord02() {
return word02;
}
public void setWord02(String word02) {
this.word02 = word02;
}
}

这样,我们就把配置文件的字段加载到了配置文件bean中,但要想使得该配置文件在IOC容器中注册bean,且让@ConfigurationProperties注解生效的话,还需要在main启动类中添加这样的注解:@EnableConfigurationProperties({ConfigBean01.class}),注意要指定配置文件的类名,如下:

@SpringBootApplication
@EnableConfigurationProperties({ConfigBean01.class})
public class Chapter02Application { public static void main(String[] args) {
SpringApplication.run(Chapter02Application.class, args);
}
}

这样在项目启动的时候会将配置文件类ConfigBean01.java的bean对象加载到IOC容器中,并使得ConfigBean01的@ConfigurationProperties注解有效,来读取配置文件的值,并绑定到字段中;

下面我们就可以在controller中调用配置文件bean了:

@RestController
public class Controller01 { @Value(value="${com.zjt.welcomeWords01}")
private String word01;
@Value(value="${com.zjt.welcomeWords02}")
private String word02; @Autowired
private ConfigBean01 configBean01;
@ResponseBody
@RequestMapping("test01")
public String test01(){
System.out.println("word01:"+word01);
return "word01:"+word01;
} @ResponseBody
@RequestMapping(value = "test02", produces = "application/json; charset=UTF-8")
public String test02(){
System.out.println("word02:"+word02);
return "word02:"+word02;
} @ResponseBody
@RequestMapping(value
= "test03", produces = "application/json; charset=UTF-8")
public String test03(){
System.out.println("word01+word02:"+word01+word02);
return "word01+word02:"+word01+
word02;
}

}

访问:http://localhost:8080/test03

可以看到,我们已经很轻松的获取到了配置文件的值;

至此,我们已经可以很轻松的通过@value以及通过配置文件bean的方式来获取配置文件的值;


2.使用YAML代替Properties

Spring框架提供两个便利的类用于加载YAML文档,YamlPropertiesFactoryBean会将YAML作为Properties来加载,YamlMapFactoryBean会将YAML作为Map来加载。

示例:

environments:
dev:
url: http://dev.bar.com
name: Developer Setup
prod:
url: http://foo.bar.com
name: My Cool App

上面的YAML文档会被转化到下面的属性中:

environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App

YAML列表被表示成使用[index]间接引用作为属性keys的形式,例如下面的YAML:

my:
servers:
- dev.bar.com
- foo.bar.com

将会转化到下面的属性中:

my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com

使用Spring DataBinder工具绑定那样的属性(这是@ConfigurationProperties做的事),你需要确定目标bean中有个java.util.List或Set类型的属性,并且需要提供一个setter或使用可变的值初始化它,比如,下面的代码将绑定上面的属性:

@ConfigurationProperties(prefix="my")
public class Config {
private List<String> servers = new ArrayList<String>();
public List<String> getServers() {
return this.servers;
}
}

注意:YAML文件不能通过@PropertySource注解加载。所以,在这种情况下,如果需要使用@PropertySource注解的方式加载值,那就要使用properties文件。

在了解了yaml之后,我们基于上面,在src\main\resources\application.properties的平行位置新建application.yml,如下:

com:
zjt:
welcomeWords01: "你好,我是来自application.yml的com.zjt.welcomeWords01"
welcomeWords02: "你好,我是来自application.yml的com.zjt.welcomeWords02"
welcomeWords03: "你好,我是来自application.yml的com.zjt.welcomeWords03"
welcomeWords04: "你好,我是来自application.yml的com.zjt.welcomeWords04"

在controller中增加test04(),如下:

package com.zjt.chapter02.controller;

import com.zjt.chapter02.bean.ConfigBean01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; @RestController
public class Controller01 { @Value(value="${com.zjt.welcomeWords01}")
private String word01;
@Value(value="${com.zjt.welcomeWords02}")
private String word02;
@Value(value="${com.zjt.welcomeWords03}")
private String word03;
@Value(value="${com.zjt.welcomeWords04}")
private
String word04; @Autowired
private ConfigBean01 configBean01; @ResponseBody
@RequestMapping("test01")
public String test01(){
System.out.println("word01:"+word01);
return "word01:"+word01;
} @ResponseBody
@RequestMapping(value = "test02", produces = "application/json; charset=UTF-8")
public String test02(){
System.out.println("word02:"+word02);
return "word02:"+word02;
} @ResponseBody
@RequestMapping(value = "test03", produces = "application/json; charset=UTF-8")
public String test03(){
System.out.println("word01+word02:"+word01+word02);
return "word01+word02:"+word01+word02;
} @ResponseBody
@RequestMapping(value
= "test04", produces = "application/json; charset=UTF-8")
public String test04(){
System.out.println("word03+word04:"+word03+word04);
return "word03+word04:"+word03+
word04;
}
}

注意,此时我们的项目中同时包含application.properties和application.yml,

我们分别访问:

http://localhost:8080/test03

http://localhost:8080/test04

由此我们初步得出:

1.当application.properties和application.yml处于同一级别目录时,application.properties中的属性会覆盖application.yml的属性值;

2.application.properties和application.yml两种配置文件可以同时存在;并均会被springboot加载;


3.springboot外化配置覆盖顺序

Spring Boot使用一个非常特别的PropertySource次序来允许对值进行合理的覆盖,需要以下面的次序考虑属性:

1. 命令行参数
2. 来自于java:comp/env的JNDI属性
3. Java系统属性(System.getProperties())
4. 操作系统环境变量
5. 只有在random.*里包含的属性会产生一个RandomValuePropertySource
6. 在打包的jar外的应用程序配置文件(application.properties,包含YAML和profile变量)
7. 在打包的jar内的应用程序配置文件(application.properties,包含YAML和profile变量)
8. 在@Configuration类上的@PropertySource注解
9. 默认属性(使用SpringApplication.setDefaultProperties指定)

比如,我们将上面的项目代码打包,mvn package;

得到:chapter02-0.0.1-SNAPSHOT.jar,这样我们其实已经将上文中的两个配置文件application.properties和application.yml同时打入了jar中;

这时,我们在该jar外同级位置,新建application.yml,

com:
zjt:
welcomeWords01: "你好,我是来自外部的application.yml的com.zjt.welcomeWords01"
welcomeWords02: "你好,我是来自外部的application.yml的com.zjt.welcomeWords02"
welcomeWords03: "你好,我是来自外部的application.yml的com.zjt.welcomeWords03"
welcomeWords04: "你好,我是来自外部的application.yml的com.zjt.welcomeWords04"

如图:

启动jar文件之后,访问:

http://localhost:8080/test03

http://localhost:8080/test04

上述现象证明:在打包的jar外的应用程序配置文件会覆盖在打包的jar内的应用程序配置文件;

除了使用外部配置文件覆盖以外,还可以通过命令附带参数来进行属性值的覆盖

我们使用 java -jar chapter02-0.0.1-SNAPSHOT.jar --com.zjt.welcomeWords04="我是来自命令行的com.zjt.welcomeWords04"

重新启动后访问

http://localhost:8080/test04

所以,当我们在进行项目开发时,你可以将一个application.properties文件捆绑到jar内,用来提供一个合理的默认name属性值。

当运行在生产环境时,可以在jar外提供一个application.properties或yml文件来覆盖name属性。

对于一次性的测试,你可以使用特定的命令行开关启动(比如,java -jar app.jar --name="Spring")。

配置文件的优先级

SpringApplication将从以下位置加载application.properties文件,并把它们添加到Spring Environment中:
1. 当前目录下的一个/config子目录
2. 当前目录
3. 一个classpath下的/config包
4. classpath根路径(root)
这个列表是按优先级排序的(列表中位置高的将覆盖位置低的)。也就是说,src/main/resources/config下application.properties覆盖src/main/resources下application.properties中相同的属性;(注:你可以使用YAML('.yml')文件替代'.properties'。)

当application.properties和application.yml处于同一级别目录时,application.properties中的属性会覆盖application.yml的属性值;(我们在第2段已经证明了这一点)

如果不喜欢将application.properties作为配置文件名,你可以通过指定spring.config.name环境属性来切换其他的名称。你也
可以使用spring.config.location环境属性来引用一个明确的路径(目录位置或文件路径列表以逗号分割)。
$ java -jar myproject.jar --spring.config.name=myproject
//or
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
如果spring.config.location包含目录(相对于文件),那它们应该以/结尾(在加载前,spring.config.name产生的名称将被追
加到后面)。不管spring.config.location是什么值,默认的搜索路径classpath:,classpath:/config,file:,file:config/总会被使用。
以这种方式,你可以在application.properties中为应用设置默认值,然后在运行的时候使用不同的文件覆盖它,同时保留默认
配置。
注:如果你使用环境变量而不是系统配置,大多数操作系统不允许以句号分割(period-separated)的key名称,但你可以使
用下划线(underscores)代替(比如,使用SPRING_CONFIG_NAME代替spring.config.name)。如果你的应用运行在一
个容器中,那么JNDI属性(java:comp/env)或servlet上下文初始化参数可以用来取代环境变量或系统属性,当然也可以使
用环境变量或系统属性。

4.配置随机值

RandomValuePropertySource在注入随机值(比如,密钥或测试用例)时很有用。它能产生整数,longs或字符串,比如:

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}

random.int*语法是OPEN value (,max) CLOSE,此处OPEN,CLOSE可以是任何字符,并且value,max是整数。如果提供
max,那么value是最小的值,max是最大的值(不包含在内)。


5.Profile-多环境配置

当我们在生产环境和开发环境使用不同的数据库时可以将数据库连接配置到两个不同的配置环境中;

Spring Profiles提供了一种隔离应用程序配置的方式,并让这些配置只能在特定的环境下生效。任何@Component或@Configuration都能被@Profile标记,从而限制加载它的时机; springboot通过使用spring.profiles.active属性来设置不同的项目环境使用的配置文件;

如:我们在application.properties相同级别位置下新建两个配置文件,application-dev.properties,application-prod.properties分别对应开发环境配置文件和生产环境配置文件;

在application.properties中添加配置:

你也可以在命令行开关中携带该属性值:

--spring.profiles.active=dev

这样,我们重启项目:

访问:http://localhost:8080/test03

当然你也可以用命令行启动的时候带上参数:

java -jar manager.jar --spring.profiles.active=prod

java -jar manager.jar --spring.profiles.active=dev

添加激活的配置(profiles)

spring.profiles.active属性和其他属性一样都遵循相同的排列规则,最高的PropertySource获胜。也就是说,你可以在application.properties中指定生效的配置,然后使用命令行开关替换它们。
有时,将特定的配置属性添加到生效的配置中而不是替换它们是有用的。spring.profiles.include属性可以用来无条件的添加生效的配置。SpringApplication的入口点也提供了一个用于设置额外配置的Java API(比如,在那些通过spring.profiles.active属性生效的配置之上):参考setAdditionalProfiles()方法。
示例:当一个应用使用下面的属性,并用 --spring.profiles.active=prod 开关运行,那proddb和prodmq配置也会生效:

---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include: proddb,prodmq

注:spring.profiles属性可以定义到一个YAML文档中,用于决定什么时候该文档被包含进配置中。

Multi-profile YAML

你可以在单个文件中定义多个特定配置(profile-specific)的YAML文档,并通过一个spring.profiles key标示应用的文档。例如:

server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production
server:
address: 192.168.1.120

在上面的例子中,如果development配置被激活,那server.address属性将是127.0.0.1。如果development和production配置(profiles)没有启用,则该属性的值将是192.168.1.100。

以编程方式设置profiles

在应用运行前,你可以通过调用SpringApplication.setAdditionalProfiles(…)方法,以编程的方式设置生效的配置。使用Spring的ConfigurableEnvironment接口激动配置也是可行的。

在代码里,我们还可以直接用@Profile注解来进行配置,例如数据库配置,这里我们先定义一个接口:

分别定义俩个实现类来实现它

通过在配置文件激活具体使用哪个实现类

然后就可以这么用了


springboot学习笔记:3.配置文件使用概要的更多相关文章

  1. SpringBoot学习笔记(2)----配置文件取值

    今天介绍三种配置文件手动取值的方式: springboot配置文件信息保存在application.properties中,默认可以spring.开头的进行spring进行一些常用参数的配置,但是很多 ...

  2. SpringBoot学习笔记:读取配置文件

    SpringBoot学习笔记:读取配置文件 配置文件 在以往的项目中,我们主要通过XML文件进行框架配置,业务的相关配置会放在属性文件中,然后通过一个属性读取的工具类来读取配置信息.在SpringBo ...

  3. SpringBoot学习笔记

    SpringBoot个人感觉比SpringMVC还要好用的一个框架,很多注解配置可以非常灵活的在代码中运用起来: springBoot学习笔记: .一.aop: 新建一个类HttpAspect,类上添 ...

  4. Springboot学习笔记(六)-配置化注入

    前言 前面写过一个Springboot学习笔记(一)-线程池的简化及使用,发现有个缺陷,打个比方,我这个线程池写在一个公用服务中,各项参数都定死了,现在有两个服务要调用它,一个服务的线程数通常很多,而 ...

  5. SpringBoot学习笔记(13):日志框架

    SpringBoot学习笔记(13):日志框架——SL4J 快速开始 说明 SpringBoot底层选用SLF4J和LogBack日志框架. SLF4J的使用 SpringBoot的底层依赖关系 1. ...

  6. SpringBoot学习笔记(10):使用MongoDB来访问数据

    SpringBoot学习笔记(10):使用MongoDB来访问数据 快速开始 本指南将引导您完成使用Spring Data MongoDB构建应用程序的过程,该应用程序将数据存储在MongoDB(基于 ...

  7. SpringBoot学习笔记(1):配置Mybatis

    SpringBoot学习笔记(1):配置Mybatis 反思:如果自己写的笔记自己都看不懂,那就不要拿出来丢人现眼! IDEA插件 Free MyBatis Plugin插件可以让我们的MyBatis ...

  8. SpringBoot学习笔记:Redis缓存

    SpringBoot学习笔记:Redis缓存 关于Redis Redis是一个使用ANSI C语言编写的免费开源.支持网络.可基于内存亦可以持久化的日志型.键值数据库.其支持多种存储类型,包括Stri ...

  9. springboot学习笔记:9.springboot+mybatis+通用mapper+多数据源

    本文承接上一篇文章:springboot学习笔记:8. springboot+druid+mysql+mybatis+通用mapper+pagehelper+mybatis-generator+fre ...

  10. SpringBoot学习笔记(14):使用SpringBootAdmin管理监控你的应用

    SpringBoot学习笔记(14):使用SpringBootAdmin管理监控你的应用 Spring Boot Admin是一个管理和监控Spring Boot应用程序的应用程序.本文参考文档: 官 ...

随机推荐

  1. js对象属性名和属性值生成新数组时都作为属性值

    const obj = { id:1, name:'zhangsan', age:18 } const arr = []; Object.getOwnPropertyNames(obj).forEac ...

  2. 用tkinter写一个记事本程序(未完成)

    之前在看tkinter与python编程 ,后面学opengl就把那本书搁置了.几天没用tkinter,怕是基本的创建组件那些都忘记了,所以想着用tkinter试着写一下记事本程序.一开始的时候以为很 ...

  3. TX2Ubuntu16.04上安装 kinectV2

    本文参考   https://www.ncnynl.com/archives/201706/1780.html 参考    https://blog.csdn.net/qq_33835307/arti ...

  4. 洛谷 P1731 [NOI1999]生日蛋糕 && POJ 1190 生日蛋糕

    题目传送门(洛谷)  OR 题目传送门(POJ) 解题思路: 一道搜索题,暴力思路比较容易想出来,但是这道题不剪枝肯定会TLE.所以这道题难点在于如何剪枝. 1.如果当前状态答案已经比我们以前某个状态 ...

  5. Python说文解字_杂谈07

    1. 深入dict from collections.abc import Mapping,MutableMapping # dict 属于mapping类型 a = {} print(isinsta ...

  6. Xcode中SVN不能提交.a及其他文件

    Xcode默认忽略的.a 文件.所以无法提交到svn服务器,但是很多第三方的库都有.a文件.所以还是必须提交到服务器. 搜索了一下解决方案: http://wpt205.blog.163.com/bl ...

  7. ThreeJS 阴影条纹BUG

    ThreeJS 开启阴影正确做法: 1. 渲染器启用阴影 renderer.shadowMap.enabled = true;2. 灯光产生阴影 light.castShadow = true;3. ...

  8. 为什么Web前端变的越来越复杂,变得更加难学了

    前端发展了也有些年头了,曾记得很多年前,聊起前端,都觉得是很简单,那个时候都没有前端工程师这个职位.可现在,前端已经逆袭了,已经不是原来的样子了,各种技术层出不穷,显的越来越高深莫测了.前端真的变得那 ...

  9. 吴裕雄--天生自然ShellX学习笔记:Shell 数组

    数组中可以存放多个值.Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小(与 PHP 类似). 与大部分编程语言类似,数组元素的下标由0开始. Shell 数组用括号来 ...

  10. ZJNU 2135 - 小智的宝可梦

    因为成环 所以可以枚举第1只与第n只喂的次数 然后第1只和第2只的次数就固定了,以此类推,则所有宝可梦喂的次数都固定了 最后处理完检查是否全为0,不是则进行下一次枚举,是则直接输出Yes 如果所有枚举 ...