Spring Boot源码之旅五十四ConfigFileApplicationListener配置文件加载原理三

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

 

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

 

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

 

基本流程图

application配置文件加载

我们考虑简单的application配置文件的加载,其实这个时候只是个名字,后面会进行前后缀的拼接。

application配置文件加载

接下来就遍历名字集合,然后进行加载,主要是下面这段,其实这里就是获取所有的属性源加载器,比如PropertiesPropertySourceLoader是加载"properties", "xml"后缀的,YamlPropertySourceLoader是加载"yml", "yaml"后缀的,所以这里就遍历出题目的后缀,然后里面进行路径拼接后尝试加载:

    private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
    				DocumentConsumer consumer) {
    			...
    			Set<String> processed = new HashSet<>();
    			for (PropertySourceLoader loader : this.propertySourceLoaders) {
    				for (String fileExtension : loader.getFileExtensions()) {
    					if (processed.add(fileExtension)) {
    					//进行了路径拼接
    						loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
    								consumer);
    					}
    				}
    			}
    		}

所以这里知道为什么yaml可以写成yml

loadForFileExtension

这里很关键的点就是profile参数是null,因为前面说过,会放一个null进去,为了加载特定的配置文件,比如classpath:/application..properties。然后直接进行load。如果已经有存在的话就会尝试去加载相关的环境配置文件。

    private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension,
    				Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
    			//进行环境配置的加载 也就是xxx-dev-xx.xx这种
    			DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null);
    			DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
    			if (profile != null) {
    				// Try profile-specific file & profile section in profile file (gh-340)
    				String profileSpecificFile = prefix + "-" + profile + fileExtension;
    				load(loader, profileSpecificFile, profile, defaultFilter, consumer);
    				load(loader, profileSpecificFile, profile, profileFilter, consumer);
    				// Try profile specific sections in files we've already processed
    				for (Profile processedProfile : this.processedProfiles) {
    					if (processedProfile != null) {
    						String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
    						load(loader, previouslyLoaded, profile, profileFilter, consumer);
    					}
    				}
    			}
    			// Also try the profile-specific section (if any) of the normal file
    			load(loader, prefix + fileExtension, profile, profileFilter, consumer);
    		}

load开始加载配置文件

不存在的话就返回,然后进行文件名的后缀符检查和是否是目录的检查。

loadDocuments加载文档

然后才开始加载loadDocuments,其实内部就是用传进来的加载器加载,当然会先看缓存里有没有,没有就加载,加载到后放缓存:


比如PropertiesPropertySourceLoader加载到的信息:


最后封装成一个OriginTrackedMapPropertySource类型的集合返回。

处理环境配置

然后进行环境配置的检查,如果配置属性里有spring.profiles.activespring.profiles.include的配置的话会进行处理,这里面就会看到我最开始说的,如果有配置了,就会把默认配置给删除。

addActiveProfiles添加激活环境

如果已经有激活环境了activatedProfiles=true,不能覆盖,返回,否则就添加到配置里,然后删除没处理的默认环境。

    	void addActiveProfiles(Set<Profile> profiles) {
    			if (profiles.isEmpty()) {
    				return;
    			}
    			if (this.activatedProfiles) {
    				if (this.logger.isDebugEnabled()) {
    					this.logger.debug("Profiles already activated, '" + profiles + "' will not be applied");
    				}
    				return;
    			}
    			//添加到配置队列里
    			this.profiles.addAll(profiles);
    			if (this.logger.isDebugEnabled()) {
    				this.logger.debug("Activated activeProfiles " + StringUtils.collectionToCommaDelimitedString(profiles));
    			}
    			this.activatedProfiles = true;
    			removeUnprocessedDefaultProfiles();
    		}
removeUnprocessedDefaultProfiles

删除配置中没有处理的默认的环境,这个就是我说的,前面为什么要先加个null,然后才是默认配置,因为如果找到了配置就会把默认配置删除了,因为有了配置当然不需要默认的啦,所以这里应该是个小技巧,不是先去找默认的,而是先去找约定的那些,约定大于配置。

    		private void removeUnprocessedDefaultProfiles() {
    			this.profiles.removeIf((profile) -> (profile != null && profile.isDefaultProfile()));
    		}

下篇继续将有了配置环境后怎么处理。

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值