Spring源码解析-环境变量

news2024/11/16 1:30:36

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

今天聊一聊Spring中环境变量的动态添加和填充Bean属性的时候一些带“$”符号的属性值的解析问题。

因为最近做项目的时候发现了一个有意思的问题,之前也没关注过。因为项目中使用的容器类型是GenericXmlApplicationContext,所以不会使用扫描的方式来读取bean,然后封装到BeanDefinitionMap中,而是采用读取xml配置文件的方式来加载bean,也就是使用bean标签的方式来配置bean,算是比较古老的方式,类似下面这种:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="people" class="com.example.spring.xmlbeans.People">
    <property name="name" value="${people.name}"/>
    <property name="age" value="${people.age}"/>
  </bean>
</beans>

可以发现,BeanA中有一个属性,且设置了set方法,然后赋值的时候是采用这种“$”的方式,让人很容易想到是从环境变量中读取一个people.name,然后在填充bean属性的时候从环境变量中拿出来就好了,其实不是这样的!!!因为刚开始我也是这么想的,然后当我清晰的看到spring的环境变量中确实有people.name这个key,但是在填充name属性的时候死活取不到值的时候,简直比阿根廷1:2爆冷输给沙特还更要懵逼!!!

先看我是怎么操作的:

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();
    }
}
public class People implements ApplicationContextAware {
  private String name;
  private Integer age;

  public void setName(String name) {
    this.name = name;
  }

  public void setAge(Integer age) {
    this.age = age;
  }

  @Override
  public String toString() {
    return "People{" +
      "name='" + name + '\'' +
      ", age=" + age +
      '}';
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    System.out.println(applicationContext.getEnvironment().getProperty("People name: "+"people.name"));
    System.out.println(applicationContext.getEnvironment().getProperty("People age: "+"people.age"));
  }
}

beans-env.properties配置文件内容如下:

people.name=messi
people.age=34

请添加图片描述

通过断点,可以很清晰的看到当前环境变量中,确实已经添加了自定义的配置文件beans-env.properties,并且可以读取people.name这个配置项,然而当程序继续运行的时候,却发生了意料之外的BUG… …

请添加图片描述

由此可以推断出,对beanDefinitionMap中bean的属性进行填充的时候,“$”符号的解析并不是从spring的环境变量中读取的!!!

然而不久前,项目组内一个老哥给了个解决方案,在beans.xml文件中添加一个bean,问题解决了!

<bean id="propertyConifgurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="location">
    <value>beans-env.properties</value>
  </property>
  <property name="fileEncoding">
    <value>utf-8</value>
  </property>
</bean>

请添加图片描述

所以现在有两个问题需要探索:

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

首先看第一个问题,怎么添加环境变量?上面代码示例很明显了:

ResourcePropertySource resourcePropertySource = new ResourcePropertySource("beans-env.properties");
context.getEnvironment().getPropertySources().addLast(resourcePropertySource);

调用上面两行代码即可,那么容器中的这个Environment对象又是在什么时候初始化的呢?

GenericXmlApplicationContext context = new GenericXmlApplicationContext();

其实就是在容器初始化的时候!!! 看源码:

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

未完待续…

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

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

相关文章

从GPT-3到CHAT-GPT(CHAT-GPT如何申请)

回顾2020年7月 2020年7月份有一个重大新闻&#xff0c;人工智能科研公司OpenAI&#xff0c;推出了它的新一代语言模型 GPT-3&#xff08;Generative Pretrained Transformer 3&#xff09;&#xff0c;这个事情在社交媒体影响甚广&#xff0c;甚至有一篇文章《一个新型 AI 震惊…

动态代理详解

目录 一、动态代理_代理模式简介 二、动态代理_JDK动态代理 dynamic 三、动态代理_CGLib动态代理 四、JDK和CGLib动态代理的区别 一、动态代理_代理模式简介 代理模式是23种设计模式之一。设计模式是前人总结的&#xff0c;在软件开发过程遇到常用问题的解决方案&#xff0…

微服务框架 SpringCloud微服务架构 微服务保护 30 初识Sentinel 30.4 引入cloud-demo

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 微服务保护 文章目录微服务框架微服务保护30 初识Sentinel30.4 引入cloud-demo30.4.1 引入cloud-demo30.4.2 微服务整合Sentinel30 初识Sent…

尝试使用CubeMX做stm32开发之十三:Clock Configuration(时钟树配置)

参考《STM32中文参考手册_V10》&#xff0c;研究CubeMX中有关时钟树配置。 一、系统时钟配置 三种不同的时钟源可被用于驱动系统时钟&#xff08;SYSCLK&#xff09;&#xff1a; HSI振荡器时钟HSE振荡器时钟PLL时钟 时钟源选择对应时钟配置寄存器&#xff08;RCC_CFGR&…

Android -- 每日一问:修改 SharedPreferences 后两种提交方式有什么区别?

知识点 SharedPreferences 类是一个接口类&#xff0c;真正的实现类是 SharedPreferencesImpl 。修改 SharedPreferences 需要获取它的 Editor&#xff0c;在对Editor进行put操作后&#xff0c;最后通过 commit 或者 apply 提交修改到内存和文件。当然有了两种都可以提交的方法…

Java进程线程介绍创建和执行销毁并理解线程安全和线程池 Native Method

目录1.进程和线程2.多线程的核心3.操作系统的多任务--以非常小的时间间隔交替执行4.native 修饰的方法5.Thread创建线程的两种方式1.普遍采用实现Runnable接口的方式2.继承Thread方式6.自定义线程用 new Thread(Runnable target) 启动源码分析6.1-new Thread(myThread)6.2对实例…

mysql8.0.21安装配置方法图文教程

记录了mysql 8.0.21 的安装配置方法&#xff0c;分享给大家。 一、下载 1、下载安装包 mysql下载路径 2、解压压缩包 3、在此目录下新建my.ini配置文件 [mysqld] # 设置 3306 端口 port3306 # 设置 mysql 的安装目录 basedirD:\mysql-8.0.21-winx64 # 设置 mysql 数据…

破案了!不会讲笑话不会作诗的chatGPT!

热出圈的chatGPT, 必须亲手试试热出圈的chatGPT, 必须亲手试试1 猜猜我是谁2 问网传图片李白风格注释代码3 写个程序看看4 帮我猜猜世界杯&#xff08;发了发了&#xff0c;偷笑脸&#xff09;5 知道李白吗&#xff1f;6 那你会写诗吗&#xff1f;6 那你讲脑经急转弯吗&#xf…

linux服务器安装docker(学习中)

linux服务器安装docker1、docker官网寻找官方文档1.1、卸载之前的docker1.2、安装yum工具类1.3、配置docker下载源的地址1.4、安装最新稳定版的docker1.5、启动docker1.6、docker镜像下载加速2、docker-卷-映射和挂载2.1、nginx1、docker官网寻找官方文档 然后根据官网文档进行…

高性能零售IT系统的建设08-9年来在互联网零售O2O行业抗黑产、薅羊毛实战记录及打法

前言 2012年左右转入互联网应用&#xff0c;由于本身在学校时就涉足过远程医疗影像中的DICOM安全领域这块&#xff0c;因此也是机缘巧合我进入互联网第一年就遇上了一次亿级的DDOS攻击以及千万级CC攻击短信系统的对抗。那时在公司一战成名&#xff0c;直接从team leader升到了主…

adb remount原理

1, 输入"fastboot flashing unlock" in adb ,waiting for the device 2, 输入"fastboot flashing unlock_critical"in adb ,waiting for the device 3, 输入"fastboot reboot" reboot the stb, press any key entering the boot mode 4, after…

tensorflow入门(三)tensorflow下神经网络参数的设置

参考 Tensorflow入门 - 云社区 - 腾讯云 神经网络中的参数是神经网络实现分类或回归问题中重要的部分。在tensorflow中&#xff0c;变量(tf.Variable)的作用就是保存和更新神经网络中的参数的。在tensorflow中&#xff0c;变量(tf.Variable)的作用就是保存和更新神经网络的参…

Educational Codeforces Round 123 (Rated for Div. 2) D. Cross Coloring

Problem - D - Codeforces 翻译&#xff1a; 有一张纸&#xff0c;可以用大小为&#x1d45b;&#x1d45a;:&#x1d45b;行和&#x1d45a;列的单元格表示。所有的细胞最初都是白色的。 &#x1d45e;操作已应用到工作表。他们的&#x1d456;-th可以描述如下: &#x1d4…

前端工程化项目的思考

这是一篇个人使用前端工程开发项目的思考&#xff0c;希望可以帮助到你。完全是一篇综合概念应该是很多东西&#xff0c;我也不清楚会有多少字&#xff0c;估计会对刚刚开始的人看起来比较迷&#xff0c;但也是没有办法的事情 1.前端脚本语言开发的作者我想应该也想不到js会发展…

Spark

1 Spark作业提交流程 2 Spark提交作业参数 1&#xff09;在提交任务时的几个重要参数 executor-cores —— 每个executor使用的内核数&#xff0c;默认为1&#xff0c;官方建议2-5个 num-executors —— 启动executors的数量&#xff0c;默认为2 executor-memory —— executor…

【OpenCV学习】第9课:形态学操作的应用-提取水平线丶垂直线

仅自学做笔记用,后续有错误会更改 理论 图像在进行形态学操作的时候&#xff0c; 可以通过自定义的结构元素实现结构元素对输入图像的一些对象敏感丶对另外一些对象不敏感&#xff0c; 这样就会让敏感的对象改变而不敏感的对象保留输出。 通过使用两个最基本的形态学操作 - 膨…

华为云服务-运维篇-弹性负载均衡

文章目录一、什么是负载均衡二、我们为什么需要负载均衡1、生活中需要它的类似场景2、生活场景中协调者&#xff08;负载均衡)作用3、协调者&#xff08;负载均衡)引入后的变化三、华为云平台-如何做负载均衡弹性负载均衡-ELB四、总结一、什么是负载均衡 负载均衡构建在原有网…

【数据挖掘】薪酬分段对应工作经验/学历画柱状图【招聘网站的职位招聘数据预处理】

文章目录一.需求背景1.1 需求分析二.数据处理(对给定职位&#xff0c;汇总薪酬分段对应工作经验要求数据&#xff0c;画柱状图&#xff1b;)2.1 事前准备2,1 处理开始三.数据处理(对给定职位&#xff0c;汇总薪酬分段对应学历要求数据&#xff0c;画柱状图&#xff1b;)四.附源…

吉林大学 超星慕课 高级语言程序设计 实验08 结构化程序设计(2022级)

本人能力有限&#xff0c;发出只为帮助有需要的人。 建议同学们自己写完后再进行讨论。 其中的代码均没能在oj上进行测试&#xff0c;因此可能有误&#xff0c;请谅解。 除此以外部分题目设计深度优先搜索&#xff0c;因此可以分别用递归和堆栈实现&#xff0c;堆栈方法为了…

JavaScript进阶教程——异步编程、封装Ajax

异步编程 什么是同步与异步&#xff1a; 同步&#xff1a;一件事没做完&#xff0c;只能等待&#xff0c;完成之后再去做另一件事 异步&#xff1a; 两件事可以同时进行 前端开发中最常见的两种异步情况&#xff1a; ajax: 向后台请求数据计时器&#xff1a; setInterval se…