SpringBoot读取配置文件顺序

news2024/9/23 21:20:32

文章目录

  • 一、前言
  • 二、SpringBoot配置文件目录读取顺序
    • 源码解析
  • 三、SpringBoot配置文件类型读取顺序
    • 源码解析

一、前言

本文通过源码分析 SpringBoot 加载配置文件目录的顺序,以及 properties、xml、yml、yaml文件的读取顺序

二、SpringBoot配置文件目录读取顺序

配置文件目录读取顺序(由高到低):

  1. file:./config/ 当前项目下的/config目录
  2. file:./ 当前项目的根目录
  3. classpath:/config/ classpath的/config目录
  4. classpath:/ classpath的根目录

源码解析

我们从 SpringApplication.run 开始,一直往里走,来到 run(java.lang.String...) 方法,如下

image-20230727153319679

加载配置文件属于准备环境,我们继续跟进 prepareEnvironment 方法

image-20230727153442043

这里在环境准备就绪之后,会触发 environmentPrepared 事件,我们跟进 listeners.environmentPrepared(environment); 方法

image-20230727153847555

这里循环了所有的 SpringApplicationRunListener 调用其 environmentPrepared 方法,这个 listeners 其实就是读取 META-INF 目录下的 spring.factories 文件里的 org.springframework.boot.SpringApplicationRunListener,见下图

image-20230727154750488

ps:这里其实也是一个扩展点,如果你需要在环境准备就绪后,做一些自定义的操作,就可以自己写个类实现 SpringApplicationRunListener 接口,然后在自己的项目 /META-INF 目录下创建一个名为 spring.factories 的文件,在文件中添加 org.springframework.boot.SpringApplicationRunListener=自定义类的全路径

扯回来,我们知道这里的 listeners 其实就是 EventPublishingRunListener (见图),继续跟进其 environmentPrepared 方法

image-20230727155553838

这里调用了 Spring 的事件广播器去做事件广播,注意这里事件类是 ApplicationEnvironmentPreparedEvent 后面有用,继续跟进 multicastEvent 方法

image-20230727155759283

这里就是 Spring 事件广播的标准写法了,根据 event 找到匹配的 ApplicationListener,调用 invokeListener 方法,进去再调用 doInvokeListener 方法,最后会调用到 ApplicationListeneronApplicationEvent 方法,具体怎么找到这些 ApplicationListener 的,这里就不展开了,在众多匹配的 ApplicationListener 里有一个 ConfigFileApplicationListener ,看名字就知道,专门用来处理配置文件的,我们看它的 onApplicationEvent 方法

image-20230727162005026

上面我们知道事件类是 ApplicationEnvironmentPreparedEvent,所以这里走的是 onApplicationEnvironmentPreparedEvent 方法,继续跟进

image-20230727164746928

这里又从 spring.factories 文件里获取了 org.springframework.boot.env.EnvironmentPostProcessor,并且把自己(ConfigFileApplicationListener)也算进去了,因为 ConfigFileApplicationListener 也实现了 EnvironmentPostProcessor 接口,然后执行了这些 EnvironmentPostProcessorpostProcessEnvironment 方法,我们这里还是重点看 ConfigFileApplicationListenerpostProcessEnvironment 方法

image-20230727165041251

继续跟进 addPropertySources 方法

image-20230727165120996

继续跟进 load 方法

image-20230727170624833

这个方法里 initializeProfiles 方法会根据 spring.profiles.active 配置来决定加载哪个配置文件,如果没有就用 spring.profiles.default 配置,如果配的是 dev,就加载 application-dev.propertiesapplication-dev.yml 这样的配置文件,如果这两个参数都没有配,就加载 application.propertiesapplication.yml 这样的配置文件,下面具体看加载的逻辑里是如何获取目录的,跟进 load 方法

image-20230727174057481

很明显了,获取扫描目录的代码在 getSearchLocations 方法里

image-20230727174159191

可以看到返回值正是这4个目录,这个值一般都是取自 DEFAULT_SEARCH_LOCATIONS 这个常量,我们看下

image-20230727174326837

这里需要注意,这个常量是按优先级从低到高倒序排列的。

三、SpringBoot配置文件类型读取顺序

配置文件类型读取顺序(由高到低):

  1. properties
  2. xml
  3. yml
  4. yaml

源码解析

在上面我们讲到获取目录,下面就是要循环每个目录,在每个目录下找配置文件了,那么配置文件类型有好几种,读取的先后顺序是怎样的呢,我们先找到 load 方法

image-20230727175410839

可以看到循环中又调用了 load 方法,跟进

image-20230727175912993

可以看到走进了一个双层嵌套循环,循环调用了 loadForFileExtension 方法,方法里就是具体加载文件的源码了,我们这里重点关注的是文件类型的读取顺序,就不深究加载文件的源码了,我们看这个双层嵌套的循环,分别循环的是什么,先是循环的 propertySourceLoaders,然后再循环 loader 的 getFileExtensions 方法返回的 String 数组,这个 propertySourceLoaders 是什么呢,我们发现又又是读取的 spring.factories 文件,这回读的是 org.springframework.boot.env.PropertySourceLoader,在文件的最上面

image-20230727180524129

可以看到先后顺序是 PropertiesPropertySourceLoaderYamlPropertySourceLoader,我们再分别看这两个 loader 的 getFileExtensions 方法

image-20230727180709878

image-20230727180800564

结论很明显了,顺序是 properties > xml > yml > yaml。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/810915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端学习——Vue (Day7)

vuex 构建 vuex [多组件数据共享] 环境 state状态 mutations状态 mapMutations actions mapActions getters 模块 module (进阶语法) 综合案例 - 购物车 axios报错解决方案 import axios from axiosexport default {namespaced: true,state () {return {list: []}},mutations…

用户体系之账户设计

文章目录 前言一、需求分析1、登录功能2、退出功能3、账号绑定功能3、其他注意事项 二、账户设计1、表设计2、QA 三、实践1、账户密码登录2、手机号登录3、第三方授权登录4、账户统一 前言 随着互联网的发展,越来越多的应用、网站需要用户进行登录才能使用。为了方…

LeetCode 刷题 数据结构 数组 283题 移动零

难度:简单 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]示例 2: 输入:…

QGraphicsView实现简易地图2『瓦片经纬度』

前文链接:QGraphicsView实现简易地图1『加载离线瓦片地图』 地图采用GCJ02 Web 墨卡托投影,最小坐标:(-180.00000000000000,-85.05112877980655),最大坐标:(180.00000000000000,85.05112877980655)。瓦片地图单张图片像…

如何通俗理解扩散模型?

扩散模型(Diffusion Model)是一类十分先进的基于扩散思想的深度学习生 成模型。生成模型除了扩散模型之外,还有出现较早的 VAE ( Variational Auto- Encoder,变分自编码器) 和 GAN ( Generative Adversarial Net ,生成对抗网络) 等。 虽然它们…

Cpp学习——类与对象(2)

思维导图: 一,构造函数 1.定义 对于构造函数首先就要知道构造函数怎么写,构造函数怎么写呢?你要知道如下两点: 1.构造函数的函数名要与类名相同 2.构造函数是没有返回值的,但可以有参数。 因为这第二点&am…

ubuntu目录分析

在Ubuntu根目录下,以下是一些常见文件夹的含义: /bin:存放可执行文件,包含一些基本的命令和工具。 /boot:存放启动时所需的文件,如内核和引导加载程序。 /dev:包含设备文件,用于与硬…

关于计算机视觉的Open3D简介

一、说明 Open3D 是一个开源库,使开发人员能够处理 3D 数据。它提供了一组用于 3D 数据处理、可视化和机器学习任务的工具。该库支持各种数据格式,例如 .ply、.obj、.stl 和 .xyz,并允许用户创建自定义数据结构并在程序中访问它们。 Open3D 广…

【雕爷学编程】MicroPython动手做(16)——掌控板之图片图像显示

知识点:什么是掌控板? 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片,支持WiFi和蓝牙双模通信,可作为物联网节点,实现物联网应用。同时掌控板上集成了OLED…

进程_PCB 的理解

目录 一. PCB 的概念 1. 为什么需要PCB 2. PCB的属性 二. task struct 1. task struct 介绍 2. 查看进程指令 3. PID 4. PPID 父进程是什么? 为什么要有父进程? 5. fork 创建子进程 1) fork 后的现象 为什么会打印两次? 2) 的返…

用C语言实现插入排序算法

1.设计思路 用插入排序对长度为n的待排序数组A进行排序的伪代码(在代码中,A中元素的数目n用A.length来表示)。 伪代码如下: INSERTION-SORT(A) for j2 to A.length:keyA[j] //将A[j]插入已排序序列A[1..j-1]ij-1while i>0…

【MTI 6.S081 Lab】Copy-on-write

【MTI 6.S081 Lab】Copy-on-write The problemThe solutionImplement copy-on-write fork (hard)实验任务Hints解决方案问题解决思考uvmcopykfreekallockpagerefcow_handlertrap 虚拟内存提供了一定程度的间接性:内核可以通过将PTE标记为无效或只读来拦截内存引用&a…

Quartz项目搭建与任务执行源码分析

数据库准备 准备一个MySQL数据库,版本为8.0,然后创建一个库,并从quartz官方的版本包中找到名称为tables_mysql_innodb.sql的脚本执行进去(脚本内容文后也有提供)。 项目依赖说明 创建一个Maven项目,引入…

Python方式实现简易弹道计算机

1 问题 本周无意间刷到了德国豹2A5坦克的火控介绍,想自己编写一个不考虑空气阻力以及测风影响的简易弹道计算机(大口径火炮)。 2 方法 由高中物理知识了解到,炮弹出膛之后基本就是抛物线列个抛物线方程就好了; 百度得火炮的弹道方…

【Django学习】(十六)session_token认证过程与区别_响应定制

一、认识session与token 这里就直接引用别人的文章,不做过多说明 网络应用中session和token本质是一样的吗,有什么区别? - 知乎 二、token响应定制 在全局配置表中配置 DEFAULT_AUTHENTICATION_CLASSES: [# 指定jwt Token认证rest_framew…

python_day17_多线程

threading模块 import timedef sing():while True:print("唱歌~~~~~~~~~~~~")time.sleep(1)def dance():while True:print("跳舞############")time.sleep(1) if __name__ __main__:sing()dance()此时为单线程 import threading import timedef sing(…

Java 异常处理的使用和思考

概念 异常处理的概念起源于早期的编程语言,如 LISP、PL/I 和 CLU。这些编程语言首次引入了异常处理机制,以便在程序执行过程中检测和处理错误情况。异常处理机制随后在 Ada、Modula-3、C、Python、Java 等编程语言中得到了广泛采用和发展。在 Java 中&a…

迁移学习《Efficient and Robust Pseudo-Labeling for Unsupervised Domain Adaptation》

1 摘要 问题:无监督域适应传统方法将超过一定置信度阈值的数据视为目标域的伪标记数据,因此选择合适的阈值会影响目标性能。 在本文中,提出了一种新的基于置信度的加权方案来获得伪标签,并提出了一种自适应阈值调整策略&#xff0…

oCPC实践录 | oCPC下机制设计变得毫无意义?(2)无声的战争

接上回oCPC实践录 | oCPC下机制设计变得毫无意义?(1)事出异常必有妖,互联网广告最开始采用的广义第一价格密封拍卖(GFP),对广告主而言,需要不断感知竞争对手的变化,修改报价&#xf…

text-generation-webui加载chatglm2-6b时,报错,要求set the option trust_remote_code=True

背景 使用text-generation-webui加载chatglm2-6b大模型时报错,要求设置option trust_remote_codeTrue,一开始没注意界面,去翻找配置文件,后来发现,就在Model界面,有一个复选框,可以进行设置&am…