往期文章回顾:
Spring Boot 第一弹,问候一下世界!!!
前言
上弹说到
如何应用 Spring Boot 问候一下世界
,想必大家都对Spring Boot
曾经有肯定的把握了。如果还没看的,没关系,能够点击下面往期回顾链接前去学习
。
明天咱们一起来学习Spring Boot 第二弹
,玩转Spring Boot 配置文件
。
说起Spring Boot 的配置文件
,真的是爱恨交加
,绝对于之前 Spring 大量的配置文件,当初的 Spring Boot 几乎几乎几乎。。。,怎一个爽字了得
。当然了,爽的同时,也迎来了不少困扰,比方: 咱们对于 Spring Boot 是如何实现
的只须要批改配置文件就能达到肯定成果也是充斥了好奇,这个就须要咱们去浏览Spring Boot 的源码 - 主动拆卸原理
了,。这里我就不再赘述了, 前面我会出专门针对源码进行剖析的文章
,敬请期待吧!!!
话不多说,开搞!!!
Spring Boot 配置文件格式
Spring Boot 官网
提供了两种罕用的配置文件格式,别离是 properties
、YML
格局。相比于 properties
来说,YML
更加年老,层级也是更加明显。强烈推荐应用 YML
格局
Spring Boot 配置文件优先级加载机制
Spring Boot 我的项目
启动会扫描以下地位的 application.properties
或者 application.yml
作为默认的配置文件.
file:./config/
file:./config/*/
file:./
classpath:/config/
classpath:/
加载的优先级程序是
从上向下加载
,并且所有的文件都会被加载
,高优先级的内容
会笼罩低优先级的内容
,造成互补配置
徒手撕源码
咱们能够从
ConfigFileApplicationListener
这个类中找到,其中 DEFAULT\_SEARCH\_LOCATIONS 属性设置了加载的目录:
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/";
private static final String DEFAULT_NAMES = "application";
private static final Set<String> NO_SEARCH_NAMES = Collections.singleton((Object)null);
private static final Bindable<String[]> STRING_ARRAY = Bindable.of(String[].class);
private static final Bindable<List<String>> STRING_LIST = Bindable.listOf(String.class);
private static final Set<String> LOAD_FILTERED_PROPERTY;
public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location";
...
...
...
}
而后在
ConfigFileApplicationListener
类中的getSearchLocations
办法中去逗号解析成 Set,其中外部类 Loader 负责这一配置文件的加载过程
,包含加载profile 指定环境的配置
,以 application+’-’+name 格局的拼接加载。
外部类 Loader 的 load 办法
private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {this.getSearchLocations().forEach((location) -> {String nonOptionalLocation = ConfigDataLocation.of(location).getValue();
boolean isDirectory = location.endsWith("/");
Set<String> names = isDirectory ? this.getSearchNames() : ConfigFileApplicationListener.NO_SEARCH_NAMES;
names.forEach((name) -> {this.load(nonOptionalLocation, name, profile, filterFactory, consumer);
});
});
}
getSearchLocations()办法
private Set<String> getSearchLocations() {Set<String> locations = this.getSearchLocations("spring.config.additional-location");
if (this.environment.containsProperty("spring.config.location")) {locations.addAll(this.getSearchLocations("spring.config.location"));
} else {locations.addAll(this.asResolvedSet(ConfigFileApplicationListener.this.searchLocations, "classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/"));
}
return locations;
}
asResolvedSet()
private Set<String> asResolvedSet(String value, String fallback) {List<String> list = Arrays.asList(StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(value != null ? this.environment.resolvePlaceholders(value) : fallback)));
Collections.reverse(list);
return new LinkedHashSet(list);
}
其实能够看出源码外面给出的
配置文件排列程序跟加载程序是相同的
。而是应用了Collections.reverse(list)
办法
- 咱们也能够通过指定配置
spring.config.location
来扭转默认配置,个别在我的项目曾经打包后,咱们能够通过以下指令来加载内部的配置
。
java -jar XXX-0.0.1-SNAPSHOT.jar --spring.config.location=F:/application.yml
- 另外也能够通过
命令行参数进行配置
所有的配置
都能够在 命令行
上进行指定
多个配置用空格离开;-- 配置项 = 值
java -jar XXX-0.0.1-SNAPSHOT.jar
--server.port=8888 --server.context-path=/qlh
上面给出优先级 从高到低
的配置文件排列程序:
- 命令行参数
- 来自 java:comp/env 的 JNDI 属性
- Java 零碎属性(System.getProperties())
- 操作系统环境变量
- RandomValuePropertySource 配置的 random.* 属性值
备注:由 jar 包内向 jar 包内进行寻找,优先加载带 profile 的,再加载不带 profile 的
- jar 包内部的 application-{profile}.properties 或 application.yml(带 spring.profile)配 - 置文件
- jar 包外部的 application-{profile}.properties 或 application.yml(带 spring.profile)配置文件
- jar 包内部的 application.properties 或 application.yml(不带 spring.profile)配置文件
- jar 包外部的 application.properties 或 application.yml(不带 spring.profile)配置文件
- @Configuration 注解类上的 @PropertySource
- 通过 SpringApplication.setDefaultProperties 指定的默认属性
properties、YAML 配置优先级加载机制
Spring Boot
应用一个以 application 命名的配置文件作为默认的全局配置文件
。反对properties 后缀结尾
的配置文件或者以 yml/yaml 后缀结尾
的 YAML 的文件配置。
以设置利用端口为例 初体验 Spring Boot 配置文件
properties 后缀结尾(application.properties)
server.port=80
yml/yaml 后缀结尾(application.yml/application.yaml)
server:
prot: 8088
注:同一目录下,properties 配置文件优先级 > yml/yaml 配置文件优先级。因而在
jar 包启动时
如果带上 properties 写法的配置
能够笼罩配置。yaml/yml 配置文件写法冒号后要加空格
properties 配置文件
语法结构为:
key=value
值类型:
数字,字符串,布尔,日期
person.name=tinygrey
person.age=18
person.status=true
person.birthday=2020/11/23
对象、Map
#Map
person.assets.phone=iphone 12
person.assets.car= 捷豹
#对象
person.dog.name= 奶狗
person.dog.age=3
数组
person.hobby[0]= 打篮球
person.hobby[1]= 睡觉
person.hobby[2]= 玩游戏
person.hobby[3]= 学习
yml/yaml 配置文件
以空格的
缩进水平来管制层级关系
。空格的个数并不重要,只有右边空格对齐则视为同一个层级
。留神不能用 tab
代替空格。且大小写敏感
。反对字面值,对象,数组
三种数据结构,也反对复合 构造
。
字面值
:字符串
,布尔类型
,数值
,日期
。字符串默认不加引号,单引号会本义特殊字符。日期格局反对 yyyy/MM/dd HH:mm:ss
对象
:由键值对
组成,形如key:(空格)value
的数据组成。冒号前面的空格是必须要有的,每组键值对占用一行,且缩进的水平要统一,也能够应用行内写法
:{k1: v1, ....kn: vn}
数组
:由形如-(空格)value
的数据组成。短横线前面的空格是必须要有的,每组数据占用一行,且缩进的水平要统一,也能够应用行内写法:[1,2,...n]
复合构造
:下面三种数据结构任意组合
值类型:
数字,字符串,布尔,日期
person:
name: tinygrey
age: 18
status: true
birthday: 2002/04/02
对象、Map
person:
#Map
assets:
phone: iphone 12
car: 捷豹
#对象
dog:
name: 奶狗
age: 3
# 行内写法
person:
#Map
assets: {phone: iphone 12,car: 捷豹}
#对象
dog: {name: 奶狗,age: 3}
数组
person:
hobby:
- 打篮球
- 睡觉
- 玩游戏
- 学习
# 行内写法
person:
hobby: [打篮球, 睡觉, 玩游戏, 学习]
注:
YML 是一种旧式的格局
,层级显明,强烈推荐应用
。留神如下:
:
字符串
能够不加引号,若加双引号则输入特殊字符
,若不加或加单引号则本义特殊字符
数组类型
,短横线前面要有空格;对象类型
,冒号前面要有空格
yaml/yml
是以空格缩进的水平来管制层级关系,但不能用 tab 键代替空格
,大小写敏感
本文所有提到的配置文件都对应上面实体类做为参考
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component
@PropertySource(value = "classpath:config/custom-profile.properties", encoding = "utf-8")
@ConfigurationProperties(prefix = "person")
public class Person {@Value("${person.name}")
private String name;
@Value("${person.age}")
private int age;
private boolean status;
@Value("${person.birthday}")
private Date birthday;
private List<String> hobby;
private Map<String, Object> assets;
private Dog dog;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component
@PropertySource(value = "classpath:config/custom-profile.properties", encoding = "utf-8")
@ConfigurationProperties(prefix = "dog")
class Dog {
private String name;
private Integer age;
}
配置文件如何跟实体类绑定
Spring Boot
所有的配置都是为了取值,Spring Boot 提供了一些取值的形式。咱们一起来看一下。
@ConfigurationProperties(prefix = "person")详解
注: 该注解用于从配置文件中取值,反对简单的数据类型,然而不反对
SPEL 表达式
。prefix 属性:
指定获配置的前缀,毕竟配置文件中的属性很多,也有很多重名的,必须用一个前缀来辨别下。
该注解能够标注在类上
也能够标注在办法上
,这里就能够看出它有两种获取值的形式
。
标注在类上
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component // 注入到 IOC 容器中
@ConfigurationProperties(prefix = "person")// 从配置文件中读取文件
public class Person {@Value("${person.name}")
private String name;
@Value("${person.age}")
private int age;
@Value("${person.birthday}")
private Date birthday;
private List<String> hobby;
private Map<String, Object> assets;
private Dog dog;
}
标注在办法上
/**
* @Bean 将返回的后果注入到 IOC 容器中
* @ConfigurationProperties 从配置文件中取值
* @return
*/
@ConfigurationProperties(prefix = "person")
@Bean
public Person person(){return new Person();
}
综上所述
@ConfigurationProperties
注解可能轻松的让配置文件跟实体类绑定在一起。
具备以下长处:
- 注入属性反对批量,仅仅指定一个
前缀 prefix
即可- 数据类型反对简单数据,比方
List、Map
- 属性名匹配规定 -
涣散绑定
,比方a-b
,a_b
,aB
,A_B
都能够取值- 反对 JAVA 的 JSR303 数据校验
值得关注的是:@ConfigurationProperties
这个注解仅仅是反对从 Spring Boot 的默认配置文件
中取值,也就是 application.properties
、application.yml
、application.yaml
,那咱们如何从自定义配置文件取值呢???
别着急,有解决办法,那就是再加一个注解:@PropertySource(value = "classpath:custom-profile.properties")
, 上面会有对@PropertySource
注解的介绍。请急躁往下面看。
@Value
@Value 这个注解咱们应该都比拟相熟了,Spring 中从属性取值的注解,反对 SPEL 表达式,不反对简单的数据类型,比方 Map、List。应用能够参考下面实体类外面的代码。
自定义配置文件并取值
Spring Boot
在启动的时候会主动加载application.xxx
, 然而有的时候为了防止 application.xxx 配置文件过于臃肿
,就须要咱们自定义配置文件
,那么自定义配置文件的话,咱们如何从自定义配置文件外面取值呢?这时候就须要配合 @PropertySource 这个注解
应用了。
应用 @PropertySource 注解
在配置类上标注 @PropertySource 并指定你自定义的配置文件即可。能够参考上面代码
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component
@PropertySource(value = {"classpath:config/custom-profile.properties"}, encoding = "utf-8")
@ConfigurationProperties(prefix = "person")
public class Person {@Value("${person.name}")
private String name;
@Value("${person.age}")
private int age;
@Value("${person.birthday}")
private Date birthday;
private List<String> hobby;
private Map<String, Object> assets;
private Dog dog;
}
对应配置文件
person.name=tinygrey
person.age=18
person.birthday=2020/11/23
person.hobby[0]= 打篮球
person.hobby[1]= 睡觉
person.hobby[2]= 玩游戏
person.hobby[3]= 学习
person.assets.phone=iphone 12
person.assets.car= 捷豹
person.dog.name= 奶狗
person.dog.age=3
@PropertySource 注解属性
value: 是一个
数组,能够指定多个配置文件
同时引入。
value 是数组那么问题就来了:如果同时加载多个配置文件
,并且不同配置文件
中对同一个属性
设置了不同的值
,那么 Spring 会辨认哪一个呢?
创立两个配置文件custom-profile.yml、custom-profile1.yml
,如上来引入。
@PropertySource(value = {"classpath:config/custom-profile.yml","classpath:config/custom-profile1.yml"})
public class Person {...}
咱们能够通过控制变量法进行测试,具体过程我这里就不赘述了。
间接说 论断
吧:Spring 加载程序
为从左到右程序加载
,后加载的会 笼罩
先加载的属性值。
另外须要留神的是 :@PropertySource
默认加载 xxx.properties 类型
的配置文件,不能加载 YML 格局
的配置文件。如何解决呢?上面来解决这一问题
加载自定义 YML 格局的配置文件
@PropertySource
注解有一个属性 factory
,默认值是PropertySourceFactory.class
,这个就是用来加载 properties 格局
的配置文件,那咱们自定义一个用来加载 YML 格局
的配置文件不就能够了嘛?上代码
/**
* 解决 @PropertySource 只对 properties 文件能够进行加载,但对于 yml 或者 yaml 不能反对。*/
public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {String sourceName = name != null ? name : resource.getResource().getFilename();
if (!resource.getResource().exists()) {
assert sourceName != null;
return new PropertiesPropertySource(sourceName, new Properties());
} else if (Objects.requireNonNull(sourceName).endsWith(".yml") || sourceName.endsWith(".yaml")) {Properties propertiesFromYaml = loadYamlProperties(resource);
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
} else {return super.createPropertySource(name, resource);
}
}
private Properties loadYamlProperties(EncodedResource resource){YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();}
}
咱们写好下面的代码之后,只须要增加
@PropertySource
注解中 factory 属性指定为YmlPropertySourceFactory
即可, 代码如下:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
@Component
@PropertySource(value = {"classpath:config/custom-profile.yml"}, encoding = "utf-8", factory = YmlPropertySourceFactory.class)
@ConfigurationProperties(prefix = "person")
public class Person {@Value("${person.name}")
private String name;
@Value("${person.age}")
private int age;
@Value("${person.birthday}")
private Date birthday;
private List<String> hobby;
private Map<String, Object> assets;
private Dog dog;
}
对应配置文件:
person:
name: qlh
age: 22
birthday: 2012/04/02
hobby:
- 打
- 睡
- 玩
- 学
assets:
phone: iphone
car: 福特野马
dog:
name: 狗
age: 1
@PropertySource
指定加载自定义的配置文件,默认只能加载 properties 格局
,然而能够指定 factory 属性来加载 YML 格局的配置文件
。
同时加载多个配置
测试是否胜利
编写 PropertiesController
@RestController
@RequestMapping("properties")
@Slf4j
public class PropertiesController {
final
Person person;
public PropertiesController(Person person) {this.person = person;}
@GetMapping("getProperties")
public Dict getProperties(){log.info(person.toString());
return Dict.create().set("person", person);
}
}
浏览器输出:
http://localhost:8081/springboot-properties/properties/getProperties
验证后果。看到打印类信息,示意加载自定义 YML 格局的配置文件
胜利了。
扩大性能
SpringBoot
还提供了@ImportResource
注解加载内部配置文件,只不过@ImportResource
通常用于加载 Spring 的 xml 配置文件
@ImportResource 应用
Spring Boot
提出零 xml 的配置
,因而Spring Boot 默认状况
下是不会被动辨认
我的项目中Spring 的 xml 配置文件
。为了可能加载 xml 的配置文件
,Spring Boot提供了 @ImportResource 注解
,该注解能够加载 Spring 的 xml 配置文件
,通常加于启动类
上。这里就不做赘述了, 代码参考上面。
//value:Spring 的 xml 配置文件, 反对多个。@ImportResource(value = {"classpath:config/beans.xml"})
@SpringBootApplication
public class SpringbootPropertiesApplication {public static void main(String[] args) {SpringApplication.run(SpringbootPropertiesApplication.class, args);
}
}
Spring Boot 多环境配置
多环境配置有什么益处呢???
不同环境配置能够配置不同的参数
便于部署,提高效率,缩小出错
yml 多环境配置
application.yml
主配置文件
server:
port: 8081
servlet:
context-path: /springboot-properties
#配置激活选项
spring:
profiles:
active: dev
application-dev.yml
开发配置文件
# 指定属于哪个环境
spring:
profiles:
- dev
application-prod.yml
生产配置文件
# 指定属于哪个环境
spring:
profiles:
- prop
application-test.yml
测试配置文件
# 指定属于哪个环境
spring:
profiles:
- test
properties 多环境配置
(1)主配置文件:配置激活选项
spring.profiles.active=dev
(2)其余配置文件:指定属于哪个环境(同 yml,只不过表现形式是 key=value
的, 三个配置文件别离是:application-dev.properties
,application-prod.properties
,application-test.properties
)
yml 多环境配置和 properties 多环境配置比拟
Properties 配置多环境
: 须要增加多个配置文件yml 配置多环境
: 可增加多个配置文件,可不增加,应用---
分隔(案例如上面代码)(不倡议应用该办法,这样显得配置文件臃肿,强烈建议增加多个配置文件
,也不麻烦。)
server:
port: 8081
servlet:
context-path: /springboot-properties
spring:
profiles:
active: dev
---
spring:
profiles:
- test
---
spring:
profiles:
- prod
---
spring:
profiles:
- dev
个别应用的配置文件
application.yml
: 是主配置文件,放一些我的项目通用的配置
application-dev.yml
: 放平时开发的一些配置,比如说数据库的连贯地址、帐号密码等
application-prod.yml
: 放生产环境的一些配置,比如说数据库的连贯地址、帐号密码等
application-test.yml
: 放测试环境须要用到的参数
激活指定 profile
应用 spring.profiles.active 激活
无论是应用上述 多文档块
的形式,还是新建 application-test.yml
文件,都能够在配置文件中指定 spring.profiles.active=test
激活指定的 profile。
打成 jar 包运行时候应用命令行激活
java -jar XXXX-0.0.1-SNAPSHOT.jar --spring.profiles.active=test
应用虚拟机参数激活
-Dspring.profiles.active=test
在 java 代码中激活
@SpringBootApplication
public class SpringbootPropertiesApplication {public static void main(String[] args) {System.setProperty("spring.profiles.active", "test");
SpringApplication.run(SpringbootPropertiesApplication.class, args);
}
}
结束语
感激浏览小生文章。祝大家早日富可敌国,实现财产自在。写文不易
, 肯定要 点赞、评论、珍藏哦
, 感激感激感激!!!
有任何问题能够在微信搜寻 公众号
:Madison 龙少
进行征询
或者微信扫描上面二维码进行征询