SpringBoot源码分析(4)--Environment(下)/配置文件加载原理

news2024/12/24 8:40:22

SpringBoot源码分析

  1. SpringBoot源码分析(1)–@SpringBootApplication注解使用和原理/SpringBoot的自动配置原理详解
  2. SpringBoot源码分析(2)–SpringBoot启动源码(万字图文源码debug讲解springboot启动原理)
  3. SpringBoot源码分析(3)–Environment简介/prepareEnvironment准备环境(万字图文源码debug分析)

文章目录

  • 一、前言
  • 二、Spring Boot 配置优先级
    • 2.1、配置文件加载优先级
      • 总结
    • 2.2、如何加载外部配置文件
  • 三、springboot常见的配置参数
    • 3.1、命令行参数
    • 3.2、System Properties与System Environment的区别
    • 3.3、系统参数(System Properties)
    • 3.4、系统环境参数(System Environment)
  • 四、Environment读取配置属性
    • 4.1、传统方式获取environment配置
    • 4.2、SpringBoot2.X 引入更强大的Binder获取environment配置方式

一、前言

上一篇《SpringBoot源码分析(3)–Environment简介/prepareEnvironment准备环境(万字图文源码debug分析)》写完后还有些问题没分析完,此篇文章接着上一篇继续讲。

本文基于spring-boot-2.2.14.BUILD-SNAPSHOT源码分析Environment及配置文件加载原理。

二、Spring Boot 配置优先级

上一篇文章源码分析中有体现过配置的优先级,此处做一下总结。

以下是常用的 Spring Boot 配置形式及配置属性加载的顺序(优先级由高到低):

  1. 命令行参数,如 java -jar springboot.jar --name="Java项目"
  2. 命令行中的 SPRING_APPLICATION_JSON 指定参数, 如 java -Dspring.application.json='{"name":"Java技术栈"}' -jar springboot.jar
  3. servletConfigInitParams 初始化参数;
  4. servletContextInitParams 初始化参数;
  5. JNDI参数(如 java:comp/env/spring.application.json);
  6. systemPropertiesJava系统参数(来源:System.getProperties()或者(-d命令行参数));
  7. systemEnvironment操作系统环境变量参数;
  8. RandomValuePropertySource 随机数,仅匹配:ramdom.*
  9. profile配置文件(`application-{profile}.properties(YAML)
  10. 配置文件(`application.properties(YAML)
  11. @Configuration 注解类上的 @PropertySource 指定的配置文件
  12. 通过SpringApplication.setDefaultProperties 指定的默认属性

以上所有形式的配置都会被加载,当存在相同配置内容时,高优先级的配置会覆盖低优先级的配置;存在不同的配置内容时,高优先级和低优先级的配置内容取并集,共同生效,形成互补配置。

我们这里说的高优先级的配置会覆盖低优先级的配置,其实原理是加载属性配置时按优先级读取配置,当读取到配置后即返回。所以给人的感觉是高优先级覆盖了低优先级。

2.1、配置文件加载优先级

我们在项目中使用最多的配置文件是application.properties、application.yml、application-test.yml等文件。此处我们讲解一下springboot加载这些配置文件的优先级。

springboot启动时默认扫描下面四个目录,优先级如下(优先级从高到低):

  1. file:./config/ ( 项目根路径下的config文件夹)
  2. file:./ (项目根路径)
  3. classpath:/config/ (类路径/resources下的config文件夹)
  4. classpath:/ (类路径/resources)

文件加载顺序如下:

  1. 先按优先级加载四个目录下的application文件,同一目录下propertites比yml优先。properties > xml > yml > yaml
  2. 然后按优先级加载四个目录下的application-{profile}文件,同一目录下propertites比yml优先。properties > xml > yml > yaml

注意:此处的加载顺序只是springboot加载文件时的顺序,并不是读取配置文件中属性的顺序。
在这里插入图片描述

配置属性加载顺序如下:

  1. 先按优先级加载四个目录下的application-{profile}文件,同一目录下propertites比yml优先。properties > xml > yml > yaml
  2. 然后按优先级加载四个目录下的application文件,同一目录下propertites比yml优先。properties > xml > yml > yaml

注意:此处的加载顺序才是Environment获取配置的顺序,即environment.getProperty(key)时的顺序
在这里插入图片描述
问题:为什么会有文件加载顺序与配置属性加载顺序两种顺序呢?

springboot默认是按照文件加载顺序,即遍历profile然后加载classpath:/,classpath:/config/,file:./,file:./config/四个目录下的properties、xml、yml、yaml文件,最后按profile为维度进行反转,所以文件加载的顺序与配置属性加载的顺序是相反的,具体原理可以看上一篇文章。

测试demo
如下图,当同时有application.propertites与application-{profile}.propertites文件时,我们可以看到属性加载时是以application-{profile}.propertites为优先的。
在这里插入图片描述

总结

1.加载目录优先级从高到低
file:./config/ :项目根目录找config文件夹下找配置文件。
file:./ :根目录下找配置文件
classpath:/config/ :resources下找cofnig文件夹下找配置文件。
classpath:/ :resources下找配置文件。

2.在同一个目录,application.yml和application.properties同时存在,先读取application.properties
文件优先级:properties > xml > yml > yaml

3.先读取到的配置文件,不会因为在后面其他目录再次读到同名的配置文件而被替换。以第一次读到的为准

4.有子module的工程,子module目录下的配置文件和子module目录下一层config目录的配置文件不会加载。只会加载resources下面的配置文件

2.2、如何加载外部配置文件

在实际业务使用中,我们可能遇到项目被打成jar包,然后将配置文件放在jar包外面,怎么能指定加载外部的配置文件呢?

springboot提供了一个配置属性spring.config.location,当配置了该值,则从该值中加载配置文件,否则从classpath:/,classpath:/config/,file:./,file:./config/这四个目录下加载文件。所以我们可以在启动命令中指定外部路径。

java  -jar ../java/*.jar --spring.config.location=../conf/application.yml,classpath:/configs/default.properties

注意事项:支持通过命令行参数的方式指定多个配置文件,使用英文半角 , 隔开即可。

如果你通过spring.config.location指定的不是一个文件而是一个目录,在路径最后务必添加一个"/"结束,然后结合spring.config.name进行组合配置文件,组合示例如下:

# 加载/configs/application.properties 或 /configs/application.yml(默认文件名)
java -jar project.jar --spring.config.location=classpath:/configs/

# 加载/configs/custome.properties 或 /configs/custome.yml
java -jar project.jar --spring.config.location=classpath:/configs/ --spring.config.name=custome

注意事项:spring.config.name该配置参数默认值为application,所以如果只是指定了spring.config.location并为目录形式,上面示例中会自动将spring.config.name追加到目录路径后,如果指定的spring.config.location并非是一个目录,这里会忽略spring.config.name的值。

上面内容中提出了一些新的概念,如命令行参数、启动参数、系统参数、系统环境参数等等。下面就稍微了解一下。

三、springboot常见的配置参数

3.1、命令行参数

--key=value的形式添加命令行参数

方式一: idea启动时添加
在这里插入图片描述
方式二: jar包启动时添加

java  -jar ../java/*.jar --spring.config.location=../conf/application.yml --logging.config=../conf/logback-spring.xml 

方式三: 启动类中添加参数

@SpringBootApplication
public class Demo3Application {
	public static void main(String[] args) {
	        //添加命令行参数
	        List<String> argsList = new ArrayList<>();
	        argsList.add("--spring.profiles.active=sit");
	        if (args != null) {
	            argsList.addAll(Arrays.asList(args));
	        }
	        SpringApplication.run(Demo3Application.class, StringUtils.toStringArray(argsList));
	}
}

在这里插入图片描述

3.2、System Properties与System Environment的区别

System Properties与System Environment的变量很相近,此处说明一下两者的区别。

System Environment 指的是操作系统的环境变量,而 System Properties 指的是java 程序jvm的系统变量

常见的JVM属性
在这里插入图片描述

3.3、系统参数(System Properties)

-Dkey=value的形式添加JVM参数

方式一: 在idea启动参数中添加
在这里插入图片描述
在这里插入图片描述
方式二: jar命令启动时添加

java -jar target/xxx.jar -Dserver.port=9090 -Dserver.context-path=/test

方式三: 代码中添加

在代码里通过System.setProperty(key, value)进行设置

在java中获取jvm的系统变量代码如下:

// 获取所有的环境变量
Properties properties = System.getProperties();
// 获取指定的环境变量 如java.class.path
String property = System.getProperty("java.class.path");

3.4、系统环境参数(System Environment)

在java中获取操作系统的环境变量的代码如下:

// 获取全部的环境变量
Map<String, String> systemEnvironment = System.getenv();
// 获取某个环境变量 比如:PATH
String path = System.getenv("PATH");

在这里插入图片描述

四、Environment读取配置属性

4.1、传统方式获取environment配置

1.springboot启动类,传统从environment中获取值的方式environment.getProperty

@SpringBootApplication(scanBasePackages = {"com.example"})
public class Demo3Application {


    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Demo3Application.class,args);
        
        Environment environment = run.getEnvironment();
        System.out.println(environment.getProperty("server.port"));
        System.out.println(environment.getProperty("people.man.name"));
    }
}

2.application.yml

server:
  port: 8080

people:
  man:
    name: 张三
    age: 12

a.b.my-first-key: hello spring environment

4.2、SpringBoot2.X 引入更强大的Binder获取environment配置方式

1.先看一个简单的示例,如何使用Binder绑定environment环境变量

@SpringBootApplication(scanBasePackages = {"com.example"})
public class Demo3Application {


    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Demo3Application.class,args);
        
        Environment environment = run.getEnvironment();
         //此处调用Binder.get方法获取一个Binder
        Binder binder = Binder.get(environment);
         Integer port = binder.bind("server.port", Integer.class).get();
        //bind绑定yml文件中的配置key到一个具体的对象中
        People people= binder.bind("people.man", People.class).get();
        System.out.println(port);
        System.out.println(people.toString());
    }
}

输出结果:

8080
People(name=张三, age=12)

通过以上示例,我们可以看到Binder可以很方便的动态绑定对象,类型转换。Binder还可以绑定Map,list等。我们可以发现源码中也有很多地方使用了Binder绑定配置对象,是一个非常好用强大的类。

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

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

相关文章

UNet训练自己的数据集

pycharm中python环境设置&#xff1a; 打开左上角File ---> Settings ---> 如下图 ---> Add 选择合适的python版本&#xff0c;进行环境设置 UNet训练自己的数据集&#xff1a; 一、训练自己的数据集 1、本文使用VOC格式进行训练。 2、训练前将标签文件放在VOCde…

谈 Dojo 应用的 UI 自动化测试

目录 前言&#xff1a; Dojo 是什么&#xff1f; Dojo 应用 UI 自动化测试面临的挑战 A. 异步请求的处理 B. 元素定位 图 1. Dojo 按钮小部件 C. Dojo 复杂性 D. 产品复杂性 E. 频繁的 UI 更改 F. Dojo 升级 Dojo 应用 UI 自动化测试框架挑选&#xff08;设计&#…

IIS WebApi: 文件上传,大小限制,提示413 (Request Entity Too Large)

问题&#xff1a;IIS WebApi文件上传&#xff0c;大小限制&#xff0c;提示413 (Request Entity Too Large) 一&#xff1a;在web.config上配置,按照以下格式&#xff0c;将下列标红加粗的地方&#xff0c;按照对应位置复制到web.config中&#xff0c;即可解决。 注&#xff…

本质安全设备标准(IEC60079-11)的理解(五)绝对可靠器件infallible components

在前面的章节中我们简单提及到绝对可靠器件&#xff0c; 这里重新摘抄如下&#xff1a; “这里顺便说一下可靠元器件&#xff08;infallible component&#xff09;的理解。它在标准里面占有不少的章节&#xff0c;而且开始理解他也有一些费劲。本人从两个方面理解它 &#x…

工艺流程图绘制流程?试试这样绘制

工艺流程图绘制流程&#xff1f;绘制工艺流程图可以帮助我们更好地理解工艺流程&#xff0c;确定生产流程&#xff0c;优化生产效率&#xff0c;并帮助人们更好地进行生产管理和质量控制。通过工艺流程图&#xff0c;我们可以清晰地了解每一步骤所需的设备和材料&#xff0c;以…

【Java】基于云计算-智慧校园电子班牌系统源码带原生微信小程序端

一、前言 智慧校园系统是利用物联网和云计算&#xff0c;强调对教学、科研、校园生活和管理的数据采集、智能处理、为管理者和各个角色按需提供智能化的数据分析、教学、学习的智能化服务环境。它包含“智慧环境、智慧学习、智慧服务、智慧管理”等层面的内容。 智慧校园描绘的…

webpack笔记一

文章目录 什么是webpack安装webpack一、创建配置项二、安装webpack局部安装(推荐)全局安装 三、安装webpack-cli(可选) 核心概念入口(entry)出口(output)loader插件(plugin)模式(mode) 项目实例webpack基本使用 html打包插件&#xff1a;html-webpack-plugin文件拷贝插件&#…

电子版简历有哪些(合集)

word、Excel、PPT简历 传统的电子版简历&#xff0c;即用文档软件编辑的简历。这一类简历的呈现模式只有单一的文字、图片或表格。传统&#xff0c;意味着被广泛求职者所使用。优点包括有&#xff1a;传统、端庄、直观。但传统也意味着没有创新。缺点包括有&#xff1a;乏味、不…

Gradle下载和配置教程:Windows、Mac和Linux系统安装指南

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

linux入门练级篇 第三讲 基本指令3

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f…

如何使用ChatGPT制作免费的数字人

传统的数字人制作过程 制作属于自己的免费的数字人是一个复杂的过程&#xff0c;需要涉及多个方面的知识和技术。以下是一个大致的步骤指南&#xff0c;以帮助你开始这个过程&#xff1a; 1. 确定数字人的目标和设计&#xff1a;首先&#xff0c;你需要确定数字人的用途和目标…

PPT里动画连续多次移动一个元素

PPT里有移动动画, 每次只可以移动一次. 其实可以再此添加移动动画, 但是注意新添加的动画移动轨迹是从原先的位置开始的: 如果想要其连续移动, 那么可以把第二次开始的起点拖动到第一次移动的终点上去:

MSP432学习笔记14:定时器A的学习整理

本文整理学习一下定时器A的相关基础知识&#xff0c;本文比较偏向理解与理论性&#xff0c; 主要是深入在官方手册层面进行对定时器A的深入研究&#xff0c;定时器 A的相关实践基本上在之前的文章中都有提及&#xff1a; 1.定时器A定时中断&#xff1a; MSP432学习笔记7&…

导航流程:从输入URL到页面展示,这中间发生了什么?

“在浏览器里&#xff0c;从输入 URL 到页面展示&#xff0c;这中间发生了什么&#xff1f; ”这是一道经典的面试题&#xff0c;能比较全面地考察应聘者知识的掌握程度&#xff0c;其中涉及到了网络、操作系统、Web 等一系列的知识。所以我在面试应聘者时也必问这道题&#xf…

Linux学习之系统默认打开的文件描述符、重定向

系统默认打开的文件描述符 一个进程默认会打开标准输入、标准输出、错误输出三个文件描述符。可以在/proc/PID/fd里边可以看到打开文件的描述符&#xff0c;PID需要改成具体的pid&#xff0c;比如可以使用A终端输入vim proctest之后按下回车键。 打开一个vim编辑窗口。 再打…

产品经理考PMP?开什么玩笑

早上好&#xff0c;我是老原。 熟悉我的粉丝都知道&#xff0c;我平常喜欢逛知乎&#xff0c;这不就关注到了一个话题 ​ 关于这个问题&#xff0c;老原我的回答当然是&#xff0c;有用。 毕竟没有人会自信到&#xff0c;可以只做产品经理的产品设计、需求分析、画画原型等&a…

云计算行业岗位介绍

云计算、大数据、人工智能作为新一代信息技术产业&#xff0c;未来发展前景不可估量&#xff0c;就业“前途”一片光明。 随着阿里云、腾讯云、华为云为首的国内云厂商的快速发展&#xff0c;释放出来的岗位也越来越多&#xff0c;很多有着“大厂梦”的小伙伴可以通过考取大厂…

shell脚本--------shell变量、条件表达式、流程控制

第三阶段基础 时 间&#xff1a;2023年7月7日 参加人&#xff1a;全班人员 内 容&#xff1a; shell变量、条件表达式、流程控制 目录 一、shell变量 二、shell条件表达式与运算符 三、break和continue语句 演示&#xff1a;break语句 continue语句 四、实例拓展 …

error: undefined symbol: _ZN5boost6locale4util17get_system_localeB5cxx11Eb

一、背景 UOS_x86系统&#xff0c;使用cmake编译了一个c的动态库&#xff0c;然后java通过JNI调用该动态库。编译阶段没有任何报错&#xff0c;但是运行该动态库时报了如下图的错误&#xff1a; 二、分析 目测最后这一串ZN5boost6locale4util17get_system_localeB5cxx11Eb表示…

AtcoderABC309场

A - NineA - Nine 题目大意 判断两个数是否相邻且水平排列&#xff0c;即它们在同一行并且相邻。可以直接打印或者找规律 思路分析 可以直接打印或者找规律 时间复杂度 O&#xff08;1&#xff09; 代码 #include<bits/stdc.h> using namespace std; int main(){i…