Spring源码解析-环境变量(下)

SpringBoot运行流程源码分析------阶段三(Spring Boot外化配置源码解析) 首先看一下ApplicationArguments接口的具体方法定义及功能介绍。//返回原始未处理的参数(通过application传入的) String [ ] getSourceArgs();//返回所有参数的集合,如参数为:--foo=bar --debug,则返回【"foo","debug"】 Set < String > getOptionNames();//选项参数中是否包含指定名称的参数 boolean containsOption(String name); 阅读详情

“不积跬步,无以至千里”。

接着聊上一篇文章中遗留的两个重要问题:

  1. 如何往Spring环境变量中添加自定义的环境变量?工作原理是什么?
  2. PropertyPlaceholderConfigurer这个类是怎么完成bean属性填充时“$”符号解析工作的?

这篇文章,我们分析一下第一个问题:怎么向Spring环境变量中添加自定义的环境变量?源码是怎么一步步实现的?

我的示例代码是这样的:

public class MainTest {
  public static void main(String[] args) throws IOException {
    GenericXmlApplicationContext context = new GenericXmlApplicationContext();
    // 新建一个ResourcePropertySource,读取自定义的配置文件
    ResourcePropertySource resourcePropertySource = new ResourcePropertySource("beans-env.properties");
    // 调用容器的Api添加PropertySource,即添加自定义的配置到Spring的上下文环境中
    context.getEnvironment().getPropertySources().addLast(resourcePropertySource);
    context.load("beans.xml");
    context.refresh();
    context.registerShutdownHook();
    context.start();
    System.out.println(context.getBean(People.class));
  }
}

看一下GenericXmlApplicationContext对象的初始化

GenericXmlApplicationContext context = new GenericXmlApplicationContext();

里面的私有变量XmlBeanDefinitionReader的初始化

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
  super(registry);
}
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
  Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  this.registry = registry;

  // Determine ResourceLoader to use.
  if (this.registry instanceof ResourceLoader) {
    this.resourceLoader = (ResourceLoader) this.registry;
  }
  else {
    this.resourceLoader = new PathMatchingResourcePatternResolver();
  }

  // Inherit Environment if possible
  if (this.registry instanceof EnvironmentCapable) {
    this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
  }
  else {
    this.environment = new StandardEnvironment();
  }
}

因为GenericXmlApplicationContext 这个对象它的接口 ApplicationContext 继承了EnvironmentCapable,所以会走下面的逻辑

this.environment = ((EnvironmentCapable) this.registry).getEnvironment();

而这个getEnvironment() 方法也会调用到父类的getEnvironment() 中去,即使是我们熟悉的AnnotationConfigApplicationConfig容器在这里也是一样,因为他们的父类是相同的,都是AbstractApplicationContext

请添加图片描述

进入 createEnvironment() 方法一看究竟

protected ConfigurableEnvironment createEnvironment() {
  return new StandardEnvironment();
}

这里会初始化一个StandardEnvironment对象,不过这个类的默认构造器似乎没有做什么操作,接着会调用它的父类的无参构造器

public AbstractEnvironment() {
  customizePropertySources(this.propertySources);
}
protected void customizePropertySources(MutablePropertySources propertySources) {
}

可以发现,在父类的无参构造器中调用了 customizePropertySources() 方法,而实现是在子类StandardEnvironment中

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
  propertySources.addLast(
    new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
  propertySources.addLast(
    new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

最终调用了 addLast() 方法添加了两个PropertySource类型的对象到propertySources中,一个是系统的环境变量,一个是JDK的环境变量,而这个propertySources正是AbstractEnvironment中的this.propertySources

我们看一下添加完之后的propertySource,跟我们分析的预期是一致的

请添加图片描述
请添加图片描述
请添加图片描述

到这里第一个问题就很明朗了,在看看我怎么添加环境变量的

ResourcePropertySource resourcePropertySource = new ResourcePropertySource("beans-env.properties");
// 调用容器的Api添加PropertySource,即添加自定义的配置到Spring的上下文环境中
context.getEnvironment().getPropertySources().addLast(resourcePropertySource);

关键是这一行代码:

context.getEnvironment().getPropertySources()

这里拿到的就是刚刚创建的环境变量,进而拿到AbstractEnvironment中的propertySources,调用 addLast() 即可完成环境变量的添加
请添加图片描述

Spring加载流程源码分析____ClassPathXmlApplicationContext源码跟踪(二)__setConfigLocations(configLocations) ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml"); 从ClassPathXmlApplicationContext进入跟踪: 这里我们记住this里的参数: configLocation:applicationContext.xml parent:null refresh:... 阅读详情

相关推荐

SpringBoot项目在properties文件中使用环境变量

2.在启动docker容器时传入环境参数。1.在配置文件中配置环境变量。

专注基础架构领域 4107

Spring之环境变量配置

Spring之环境变量配置

Lucifer ZHAO 3548

STM32 超声波模块输入捕获测距(标准库)

通道2设置为下降沿触发,触发瞬间会将CNT的记录到CCR2中,由于上升沿触发时已经将CNT置零所以此时的CNT的值就是高电平的持续时间。通道1设置为上升沿触发,触发的瞬间会将CNT的值记录到CCR1里面,同时设置通道1触发带有从模式,并把从模式设置为置零CNT。超声波传感器模块上面通常有两个超声波元器件,一个用于发射,一个用于接收。电路板上有四个引脚:VCC、GND、Trig(触发)、Echo(回应)。输入捕获原理可以看看这位大佬,感觉写的很清楚,工作电压与电流:5V,15mA。感测角度:不小于15度。

qq_62425900的博客 2082

Spring源码解析-环境变量(上)

spring源码解析

知秋的博客 990

单细胞双胞过滤-scrublet安装

pip install scrublet ----use-pep517有如下报错,分析可知安装annoy时不会自动更新gcc的版本,centos默认是4.8.5。pip install scrublet ----use-pep517 仍然报错,但似乎不影响使用,提示Successfully installed。打开终端,进入Python环境,输入以下代码,查看Python安装位置。暂时还没尝试是否存在问题,如果存在问题,降级scrublet版本。包的开发依赖的是比较低版本的numpy,会用到。

hzau_t的博客 792

NXP S32K5 MCU如何赋能Zonal架构与软件定义汽车?

汽车电子架构正从分布式ECU向域集中、再向Zonal分区架构演进,核心驱动力在于线束简化、算力下沉与软件分层解耦。区域控制器作为物理区域的“调度员”,需要同时满足实时响应、功能安全、多网络协议转换和OTA升级等要求,这使MCU与SoC的选型成为系统工程的关键决策。MCU凭借确定性的微秒级启动、低功耗、丰富的IO控制以及成熟的ASIL-D认证路径,仍是区域控制器的主流选择。NXP S32K5正是面向这一场景发布的系列MCU:它集成多核锁步、CAN-XL、TSN以太网、硬件安全模块与双Bank Flash,补齐

weixin_28721917的博客 355

Spring-外置环境变量解析

前言 配置文件, 常用的是properties文件, 但其只能表示简单对象(单个变量和数组变量), 后来spring-boot引入了yaml配置文件并提供了自动配置(将配置映射为复杂对象)功能, 使得开发效率大大提升, 本文将从properties和yaml两大方面说说在Spring工程中(部分引入boot的jar包)如何读取. Properties PropertySourcesPlaceholderConfigurer 启动时读取指定的配置文件并载入到Environment中 @Configuratio

1112

KUKA机器人 - 从开机到自动运行

注1:本文仅代表本人对机器人使用的一些建议,在使用机器人前,还请详细阅读库卡机器人官方资料,道路千万条,安全第一条!!! 注2:技术有限,欢迎各位大大在阅读过程中发现各类问题,并且批评指正!!! 目录 一、准备工作 1. 机器人上电完成 2. 电脑安装Workvisual 二、学习手动移动机器人 三、项目配置 1. 设置机器人IP地址 2.电脑和机器人通过网线连接 3.查找并打开项目 4. 通讯配置 5. 项目上传 6. 检验IO配置 四、编程 1.新建程序 2. 程序...

yilunyao的博客 1万+

spring获取环境变量

需求 想分辨一下test/prod环境,然后根据环境做一下逻辑处理,比如为测试环境添加了一个通用密码。。。当然这样不太好,不要学我。 实现 一开始我是想通过application.yml文件里面设置的 spring: profiles: active: local 来判断的,后来代码写了个bug误以为没起效,就又研究了一下其他方式,当然这种方式实际上是没问题的。现在把这几种方式都记录一下,以供参考。 读取配置文件方式 首先配置文件内容如下: spring: profiles: ac

盖丽男 4786

Kafka 系列 —(17)Kafka 流式处理:Kafka Streams架构、使用场景、框架选择

本文介绍了KafkaStreams的架构特点、应用场景及与其他流处理框架的比较。KafkaStreams作为嵌入式分布式流处理库,其核心架构包含流处理器、任务、拓扑和本地状态存储,具备自动容错和伸缩能力。适用于实时监控、ETL、聚合、Join、物化视图等低延迟场景。与Flink、Spark相比,KafkaStreams适合简单架构和微服务,而Flink适合大规模处理,Spark更适合批处理。选择框架需根据具体场景需求,如微服务推荐KafkaStreams,大规模处理推荐Flink。

moton2017的博客 1629

mcgs数据查表功能,用于大量数据对比查找对应数据,减少PLC代码

mcgs脚本实现数据查表功能

qq_24866535的博客 3268

Spring IoC 源码深入解析

Spring IoC 源码深入解析

qq_51999417的博客 489

Telegram Bot Api使用教程

其中token为你的机器人token,method为telegram给定的方法,在获取群组chat_id那一步就使用了telegram的其中一个方法(getUpdates),其他方法后面会介绍。telegram发送消息的方式类似与钉钉机器人,都是向一个api发送http请求,而且对于同一个APItelegram支持GET和POST两种请求方式.请求的api格式如下。通常来说我们都需要让机器人在一个群组里工作,所以首先我们需要将机器人添加到我们指定的群组,在群组里发送随意消息并@这个机器人,比如...

豫迷糊的码上生活 1万+

application中获取系统环境变量值与配置的名重复问题

application.yml配置文件中的配置: test: url: ${D_ALG_URL:https://baidu.com}/bb 环境变量中的配置: EXPORT TEST_URL="aa" 那么 @Value("${test.url}") private String url; 获取到的值为"aa" 以下为找源码找到的原因 spring源码中 QualifierAnnotationAutowireCandidateResolver#getSuggestedValue方法 找到调用者D

qq_38477936的博客 723

prplOS适配USB LAN网卡

本文介绍了将USB LAN网卡(如rndis0)适配到prplOS的LAN管理流程。

四儿家的小祖宗的博客 321

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Spring Boot源码之旅四十九@Value原理详解

作者简介:大家好,我是哥,前中兴通讯、美团架构师,现某互联网公司联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬学习必须往深处挖,挖的越深,基础越扎实!

smart_an的专栏 769

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Spring properties 文件解析

properties 文件解析 写在前面: 是因为 username 的问题,之前用的 liunx 系统然后换成 win 后,properties 文件中的 username 就解析成操作系统的用户名了。其实也简单,换一个 key 就好,只是我比较想知道是哪儿做的操作。 简单配置 properties 文件 jdbc.driver=com.mysql.jdbc.Driver j...

V_Junk的博客 602

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Spring源码深度解析(郝佳)-学习-测试,线上环境区分源码分析

本文主要是想说明Spring 中如何区分线上线下环境,并且源码中是如何实现的。 User.java @Data public class User { private String username; private Integer age; public User() { } public User(String username, Integer age) { this.username = username; this.age =

黄裳博客 475

Spring 源码-BeanFactory使用的准备及自定义属性值解析器 (5)

本文将继续介绍Spring源码的重要方法 AbstractApplicationContext#refresh方法的第三个方法:prepareBeanFactory,准备BeanFactory。 源码如下: protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loade

qq_39652397的博客 562

《Spring源码深度解析》:ClassPathXmlApplicationContext初始化步骤

1.准备工作:对系统属性及环境变量的初始化及验证。 2.初始化BeanFactory,并进行XML文件读取,将得到的BeanFactory记录在当前实体的属性中。 (1)实例化DefaultListableBeanFactory;(2)指定序列化ID;(3)定制BeanFactory相关属性,包括是否允许覆盖同名称的不同定义的对象(allBeanDefinitionOverriding)和是否允许bean之间循环依赖(allowCircularReference);(4)加载BeanDefinition,初

liuffei的专栏 583

spring的@Conditional注解使用

@Conditional是什么?可以干什么? @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。 类图 源码学习 codition是通过判断条件若成立则注册bean否则不注册 public interface Condition { /** * 条件判断 true为匹配,false为不匹配 */ boolean matches(ConditionContext context, Annotate.

逍遥壮士 515

从Profile看Spring的属性替换

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33904756的博客 767

@Value 详解及详细源码展示

Value位于/*** SpEL 表达式(用于从配置文件、环境变量等获取值)*//*** 是否必需(默认 true,属性不存在时抛出异常)*/关键属性说明value:必填属性,指定 SpEL 表达式(通常以${}包裹配置文件中的属性名)。required:可选属性(默认true),若为false,当配置属性不存在时注入null(不会抛异常)。@Value是 Spring 中从配置文件注入属性值的核心注解,支持基础类型、SpEL 表达式、可选属性等多种场景。通过结合。

csdn_tom_168的博客 1767

【spring源码系列-03】xml配置文件启动spring时refresh的前置工作

sml配置文件启动spring时refresh的前置工作

zhenghuishengq的博客 1万+

【Spring】Spring原理源码解析(五)-- Spring识别jvm、环境配置及通过@PropertySources加入配置原理

本篇主要介绍了spring如何通过内置的bean工厂后置处理器,解析配置类,识别配置类注解@PropertySources/@PropertySource;实际上就是通过在环境enviroment中,先会存储封装好的资源对象集合propertySources,然后当从enviroment获取时,实际上就会遍历这个集合,拿到第一个匹配上key的属性配置,然后去解析它所有的占位符后,得到属性值返回;

ArvinZsh的博客 480

Spring Boot中配置⽂件的加载顺序是怎样的?

jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置⽂件 再来加载不带profile。“Spring Boot 的配置加载顺序遵循‘由内到外’的原则,从命令行参数到环境变量,再到多层级的配置文件,确保运维人员能灵活覆盖开发者的默认配置。jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置⽂件。

完全体 2635
上一篇: Spring源码解析-环境变量(上)
下一篇: Linux运行环境搭建系列-Docker及MySQL8安装
知秋丶
博客等级 码龄7年 83粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值