百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

SpringBoot外化配置源码解析Profile处理实现

toyiye 2024-05-25 20:11 20 浏览 0 评论

基于Profile 的处理实现

在日常使用中我们可以通过配置 spring.profiles.active 指定一组不同环境的配置文件,比如application-dev.properties、application-test.properties、application-prod.properties。那么,profile 是如何被加载使用的呢?本节带大家重点分析一下 ConfigFileApplicationListener 类中基于 profile 的文件加载处理逻辑。

在 ConfigFileApplicationListener 类中单独定义了一个内部类 Profile 用来存储 profile 的相关信息,该类只有两个核心字段:name 用来表示 profile 文件的名称;defaultProfile 用来表示 profile 是否为默认的。

private static class Profile {
private final String name ;
private final boolean defaultProfile;}

在 ConfigFileApplicationL istener 类的逻辑处理中(除了关于配置文件的具体加载)都离不开profile 的参与。我们先从内部私有类 Loader 的 load 方法开始,代码如下。

void load() {
/过糖符合案件的 properties
FilteredPropertySource . apply(this . environment, DEFAULT PROPERTIES, LOAD_ F
ILTERED_ PROPERTY,
(defaultProperties) -> {
//创建默认的 Profile 双队列
this.profiles = new LinkedList<>();
//创建默认的已处理 Profile 列表
this . processedProfiles = new LinkedList<>
();
//默认设置为未激活
this. activatedProfiles = false;
//创建 key 为 Profile,值为 MutablePropertySo
urces 的默计 Map,注意是有序的 Map
this. loaded = new LinkedHashMap<>();
//加载配置 profile 信息, 默认为 default
initializeProfiles();
//遍历 profiles, 并加戟解析
while (!this. profiles . isEmpty()) {
Profile profile = this . profiles. poll();
//非默认的 profile 则加入
if (isDefaultProfile(profile)) {
addProfileToEnvironment (profile . getNam
e());
//解析处理 profile
load(profile, this: :getPositiveProfileFi
lter,
addToLoaded(MutablePropertySource
s: :addLast, false));
/已处理过的放入对应的列表
this. processedProfiles . add(profile);
//再次加戴 profile 为 null 的配置,将其放置在 L
oaded 的最前面
load(null, this: : getNegativeProfileFilter,
addToLoaded(Mutable-PropertySources: :addFirst, true));
//添加加载的 PropertySource 到环境中
addL oadedPropertySources();
//过滤并添加 defaul tProperties 到 processedP
rofiles 和环境中
applyActiveProfiles (defaultProperties);
});
}

以上代码执行的操作就是处理指定的 profile 与默认的 profile 之间的优先级,以及顺序关系,而其中的 load 方法是对 profile 的加载操作。

需注意的是,在 Spring Boot 2.1.x 版本中新增了 FilteredPropertySource 用来对属性文件进行过滤。同时,在 applyActiveProfiles 方 法内也涉及 Binder 类(2.2.0 新增), 它提供了关于属性配置的对象容器功能。

load 方法中 initializeProfiles 方法之前都是私有类 L oader 成员变量的初始化操作。下面我们看一 下 initializeProfiles 方法对默认 profile 的初始化操作。

private void initializeProfiles() {
//首先添加 default profile,确保首先被执行,并且优先级最低
this . profiles. add(null);
//查找环境中 spring. profiles . active 属性配置的 Profile
Set<Profile> activatedViaProperty = getProfilesFromProperty(ACTIVE_ PROFIL
ES_ PROPERTY);
//查找环境中 spring. profiles. include 属性配置的 Profile
Set<Profile> includedViaProperty = getProfilesFromProperty(INCLUDE PROFIL
ES_ PROPERTY);
//查找环境中除以上两类之外的其他属性配置的 Profile
List<Profile> otherActiveProfiles = getotherActiveProfiles (activatedViaPr
operty, includedViaProperty);
//其他属性配置添加到 profiles 队列中
this . profiles . addAll(otherActiveProfiles);
//将 included 属 性添加到队列中
this . profiles. addAll (includedViaProperty);
//将 activatedViaProperty 添加入 profiles 队列, 并没置 activatedProfiles 为激活
状态
addActiveProfiles (activatedViaProperty);
//如果没有任何 profile 配置,也 就是默认只添加了一个 null,则执行内部逻辑
if (this. profiles.size() == 1) {// AbstractEnvironment 中有默认的 default 属性, 则将 default profile 添加到 pr
ofiles 中
for (String defaultProfileName : this . environment . getDefaultProfiles())
{
Profile defaultProfile = new Profile(defaultProfileName, true);
this . profiles . add(defaultProfile);
}
}

在这个初始化的过程中,initializeProfiles 首先会给 profiles 添加一一个优先级最低的 null值,然后判断 spring. profiles active、spring .profiles include 属性配置的 profile,如果存在配置项则激活 activatedProfiles 配置。如果不存在,则 profiles 的长度为 1,进入设置默认的profile 配置。

当 initializeProfiles 方法执行完成后,程序执行回到主代码逻辑,此时会遍历 profiles 中的值,并逐一进行 load 操作。处理完成的会单独放在 processedProfiles 中,最后再次加载profile 为 null 的配置,加载 PropertySource 到环境中。

其中遍历循环过程中调用的 load 方法代码如下。

private void load(Profile profile, DocumentFilterFactory filterFactory,
DocumentConsumer consumer)
getSearchLocat ions(). forEach( (location) -> {
boolean isFolder = location endsWith("/");
Set<String> names = isFolder ? getSearchNames() : NO_ SEARCH_ NAMES;
names . forEach(
(name) -> load(location, name, profile, filterFactory, consumer));
}

在上面的代码中,主要通过 getSearchL ocations 方法获得默认的扫描路径,如果没有特殊指 定 , 就 采 用 常 量 DEFAULT_ SEARCH_ LOCATIONS中定义的4个路 径 。 而getSearchNames 方 法获得的就是 application 这个默认的配置文件名。然后,逐一遍历加载目录路径及其指定文件名的文件。

当扫描到符合条件的文件时程序会进行相应的解析操作,比如我们将指定 active 的配置放在默认的配置文件中,那么第一轮 for 循环就会将该 参数读取出来,并添加到 profiles 中,并且把 profile 中的 default 配置项移除。

private void load(PropertySourceLoader loader, String location, Profile prafile,
DocumentFilter filter, DocumentConsumer consumer) {
try {List<Document> loaded = new ArrayList<>();
for (Document document : documents) {
f (filter .match(document))
addActiveProfiles (document . getActiveProfiles());
addInc ludedProfiles (document . getIncludeProfiles());
loaded . add(document);
}
}catch (Exception ex) {
}
}

重点看上面代码中 for 循环的操作,如果解析配置文件中获得 profile 的配置项,会对这些配置项进行再次处理,也就是调用 addActiveProfiles 方法。addActiveProfiles 方法的代码如下。

void addActiveProfiles(Set<Profile> profiles) {
//如果未经激活则将其添加到 profiles 队列中
this . profiles . addAll(profiles);
if (this . logger. isDebugEnabled()) {
this. logger. debug("Activated activeProfiles
+ StringUtils. collectionToCommaDelimitedString(profil
es));
// profile 设置被激活
this . activatedProfiles = true;
//移除未处理的默 profile
removeUnprocessedDefaultProfiles();
}

这里会将配置文件中获得的 profile 添加到 profiles 中去,并设置 profile 为激活状态。最后,再调用 removeUnprocessedDefaultProfiles 方 法将默认值移除。很显然,既然已经获得了指定的 profile 配置,那么程序自动设置的默认值也就失效了。

最后再看一下 load 方法 中 add oadedPropertySources 方法,该方法将加载的配置文件有序地设置到环境中。而配置文件有序性也是通过 loaded 的数据结构来实现的,在初始化的时候已经看到它是一个 LinkedHashMap。

private void addL oadedPropertySources() {
MutablePropertySources destination = this . environment. getPropertySources
();
List<MutablePropertySources> loaded = new ArrayL ist<>(this. loaded. values
());//倒序,后指定的 profile 在前面
Collections. reverse(loaded) ;
String lastAdded = null;
Set<String> added = new HashSet<>( );
for (MutablePropertySources sources : loaded) {
for (PropertySource<?> source : sources) {
if (added. add(source . getName())) {
addLoadedPropertySource( destination, lastAdded, source);
lastAdded = source . getName();
}
}
}
}

一般情况 下 loaded 属性中会存储两个 MutablePropertySources, -一个为默认的,一个为通过 active 指定的,而 MutablePropertySources 中又存储着 属性配置文件的路径列表。

通过上面的双层遍历会获得默认的属性配置文件和指定的属性配置文件,同时将它们添加到环境中去。

这里我们从整体了解了 Profile 的操作流程,上一 节中已经举例讲解配置文件的解析、加载等过程,不在此赘述。

本文给大家讲解的内容是SpringBoot外化配置源码解析基于Profile 的处理实现

  1. 下篇文章给大家讲解的是SpringBoot外化配置源码解析综合实战;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码