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

本文主要是介绍SpringBoot外化配置源码解析:Profile处理实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于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. 感谢大家的支持!

 

这篇关于SpringBoot外化配置源码解析:Profile处理实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/610617

相关文章

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

IDEA中配置Tomcat全过程

《IDEA中配置Tomcat全过程》文章介绍了在IDEA中配置Tomcat的六步流程,包括添加服务器、配置部署选项、设置应用服务器及启动,并提及Maven依赖可能因约定大于配置导致问题,需检查依赖版本... 目录第一步第二步第三步第四步第五步第六步总结第一步选择这个方框第二步选择+号,找到Tomca

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Win10安装Maven与环境变量配置过程

《Win10安装Maven与环境变量配置过程》本文介绍Maven的安装与配置方法,涵盖下载、环境变量设置、本地仓库及镜像配置,指导如何在IDEA中正确配置Maven,适用于Java及其他语言项目的构建... 目录Maven 是什么?一、下载二、安装三、配置环境四、验证测试五、配置本地仓库六、配置国内镜像地址

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Springboot项目启动失败提示找不到dao类的解决

《Springboot项目启动失败提示找不到dao类的解决》SpringBoot启动失败,因ProductServiceImpl未正确注入ProductDao,原因:Dao未注册为Bean,解决:在启... 目录错误描述原因解决方法总结***************************APPLICA编

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security