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

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: 8080people:man:name: 张三age: 12a.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方法获取一个BinderBinder 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.hqwc.cn/news/18507.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

已解决‘mongo‘ 不是内部或外部命令,也不是可运行的程序

已解决&#xff08;MongoDB安装报错&#xff09;‘mongo’ 不是内部或外部命令,也不是可运行的程序 报错代码 粉丝群里的一个小伙伴安装完MongoDB后&#xff0c;在cmd中启动&#xff0c;却说不是可运行的命令&#xff1f; 报错原因 报错原因&#xff1a;由于没有配置环境变量的…

《TCP/IP网络编程》第3,4章学习记录

基础知识&#xff1a; struct sockaddr_in {sa_family_t sin_family; //地址族&#xff08;Address Family)uint16_t sin_port; //16位TCP/UDP端口号struct in_addr sin_addr; //32位IP地址char sin_zero[8]; //不使用 }sa_family_t包括&#xff1a; (1)AF_INET,IPv4网络协议…

CVE-2023-28432-MinIO集群模式信息泄露漏洞流量分析

简介 MinIO是一个开源对象存储系统。 在其RELEASE.2023-03-20T20-16-18Z版本&#xff08;不含&#xff09;以前&#xff0c;集群模式部署下存在一处信息泄露漏洞&#xff0c;攻击者可以通过发送一个POST数据包获取进程所有的环境变量&#xff0c;其中就包含账号密码MINIO_SEC…

轻量服务器域名无法解析怎么排查?

​  轻量服务器域名无法解析是指在DNS(域名系统)解析过程中&#xff0c;无法将域名转换为相应的IP地址。DNS可帮助该域名与代表该网站在互联网上的位置的数字 IP 地址相关联&#xff0c;帮助我们找到并连接到目标网站。因此&#xff0c;当我们无法解析域名时&#xff0c;就无…

6 君正ISP的封装

概述 ISP&#xff0c;即图像信号处理单元&#xff0c;主要包含图像效果设置&#xff0c;模式切换以及Sensor的注册、添加、删除等操作。ISP模块与数据流无关&#xff0c;不需要进行绑定&#xff0c;仅作用于效果参数设置及Sensor控制。 ISP接口类 君正的ISP模块除了能够设置亮度…

使用 Docker Desktop 安装 Centos 系统

一、前言 由于 Docker 是一个容器&#xff0c;它支持在一个服务器进行多服务部署&#xff0c;并且还能保持服务的独立性&#xff0c;那么&#xff0c;在Docker 上的运用时 我们也是可以 独立部署多个系统来做不同是其他&#xff0c;这样环境独立的情况下&#xff0c;也就不会造…

数字美容的艺术:深入探讨面部美化算法和人脸美型SDK

在当今社交媒体和自拍热潮的背景下&#xff0c;数字美容成为了许多人追求面部完美外貌的选择。通过面部美化算法和人脸美型SDK&#xff0c;人们可以在瞬间实现肌肤光滑、五官精致的效果。然而&#xff0c;这种技术的背后隐藏着怎样的原理和技术手段&#xff1f;本文将深入探讨面…

开源LLM大模型微调简明教程

我相信你们大多数人都听说过 ChatGPT 并尝试过它来回答你的问题&#xff01; 有没有想过幕后发生了什么&#xff1f; 它由 Open AI 开发的大型语言模型 GPT-3 提供支持。 这些大型语言模型&#xff08;通常称为LLM&#xff09;开启了自然语言处理的许多可能性。 推荐&#xff1…

Android 圆环统计图(带外延折线可点击)

需求先看UI效果图吧 看到这肯定去找轮子&#xff0c;找了半天&#xff0c;没找到相似的&#xff0c;大部分搜到的都是点击外凸&#xff0c;而这个UI是内凸&#xff0c;其实外凸内凸区别还不小&#xff0c;没找到一样的&#xff0c;于是乎&#xff0c;和iOS说好了要不就放弃吧&…

2023年大语言模型神器 - LangChain

概要 今天介绍一下 LangChain 框架&#xff0c;LangChain 是一个帮助在应用程序中使用大型语言模型&#xff08;LLM&#xff09;的编程框架。它可以将大型语言模型与其他计算或知识来源相结合&#xff0c;从而实现功能更加强大的应用。 最初 LangChain 是一个开源项目&#xf…

open3d实现搜索在一个球内部的点云

目录 写在前面原理代码结果参考完 写在前面 1、本文内容 给定一个点云P和一个圆心为center&#xff0c;半径为r的球&#xff0c;搜索出P中属于球内的点 2、平台/环境 使用open3d, cmake&#xff0c;适用windows/linux 3、转载请注明出处&#xff1a; https://blog.csdn.net/q…

【uniapp开发小程序】实现同声传译(长按语音转文字)

效果图&#xff1a; 插件&#xff1a; 采用小程序插件&#xff1a;微信同声传译。插件文档定位 具体步骤&#xff1a; 先登录小程序后台&#xff08;项目别错了&#xff09;&#xff1a;官网传送然后 设置 > 第三方设置 > 添加插件 在插件文档里面拿到Appid和版本号 在…