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

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Zookeeper安装和配置说明

一、Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。 ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境; ■ 伪集群模式:就是在一台物理机上运行多个Zookeeper 实例; ■ 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble) Zookeeper通过复制来实现

CentOS7安装配置mysql5.7 tar免安装版

一、CentOS7.4系统自带mariadb # 查看系统自带的Mariadb[root@localhost~]# rpm -qa|grep mariadbmariadb-libs-5.5.44-2.el7.centos.x86_64# 卸载系统自带的Mariadb[root@localhost ~]# rpm -e --nodeps mariadb-libs-5.5.44-2.el7