Spring源码:Spring创建容器总结

Spring创建容器总结

  • 创建Spring容器对象
  • Spring加载spring.properties配置文件
  • Spring是否支持spel
  • Spring设置需要加载的配置文件路径
  • Spring解析占位符
  • Spring创建标准环境StandardEnvironment
  • Spring创建占位符解析器
  • Spring创建占位符助手

使用ClassPathXmlApplicationContext创建Spring容器时,做了以下几件事:
1、会先加载spring.properties配置文件;
2、然后获取Spring是否忽略spel的标识shouldIgnoreSpel;
3、创建标准环境StandardEnvironment;
4、创建占位符解析器;
5、创建占位符助手,用于占位符的替换;
6、将构造方法中的配置文件路径解析占位符之后设置给spring容器。

创建Spring容器对象

  创建一个main方法,在Java的系统属性中设置一个键值对,用于配置文件路径中的占位符解析。使用ClassPathXmlApplicationContext创建一个spring容器,并指定需要加载的配置文件的路径,路径中包含占位符。

public static void main(String[] args) {System.setProperty("xml", "/*.xml");ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath*:${xml}");
}

  在使用构造方法创建对象时,会先调用父类的无参构造方法。在创建ClassPathXmlApplicationContext容器时会先加载父类AbstractApplicationContext中的静态成员变量。该成员变量表示是否忽略spel,即是否spring是否支持spel,当值为false时,表示不会略spel,即spring支持spel。如果为true表示spring不支持spel。源码如下:

// 静态变量,加载该类的时候就会加载静态变量。
// SpringProperties类中有静态代码块。会通过类加载器的getResource获取URL,参数为spring.properties
private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");

Spring加载spring.properties配置文件

  上文中提到,在加载AbstractApplicationContext抽象类中的静态属性时,会调用SpringProperties的静态方法,在调用静态方法之前会先执行SpringProperties类中的静态代码块。静态代码块中会加载spring.properties配置文件,将文件中的内容以键值对的形式保存到SpringProperties中。源码如下:

static {try {// 获取SpringProperties类的类加载器ClassLoader cl = SpringProperties.class.getClassLoader();// 使用类加载器将spring.properties配置文件解析成URLURL url = (cl != null ? cl.getResource(PROPERTIES_RESOURCE_LOCATION) :ClassLoader.getSystemResource(PROPERTIES_RESOURCE_LOCATION));// 如果获取到spring.properties配置文件,会读取到配置文件中的属性并设置到spring的系统属性中if (url != null) {// 将配置文件加载到输入流中try (InputStream is = url.openStream()) {// 加载配置文件的键值对,添加到spring的系统属性中localProperties.load(is);}}}catch (IOException ex) {System.err.println("Could not load 'spring.properties' file from local classpath: " + ex);}
}

Spring是否支持spel

  Spring是否支持spel关系到是否解析占位符。Spring默认支持spel,即会正常解析占位符。我们可以通过以下三种方式修改spring的配置,让spring不再支持spel:
1、在Spring系统属性中设置键值对

SpringProperties.setProperty("spring.spel.ignore", "true");

2、在spring.properties配置文件中添加以下键值对

spring.spel.ignore=true

3、在Java的系统属性中设置键值对

System.setProperty("spring.spel.ignore", "true");

  设置键值对时key是固定的,但是只有值设置为true时,上文中提到的shouldIgnoreSpel获取到的值为true,否则获取到的是false。如果同时采用以上三种方式设置,那么是第一种方式生效。因为使用第一种方式时,会先加载spring.properties配置文件,然后在调用set方法,会将原先的值覆盖掉。只有前两种方式都没有时,第三种方式才会生效。

Spring设置需要加载的配置文件路径

  执行完以上逻辑之后,会执行ClassPathXmlApplicationContext的构造方法,设置配置文件的路径。调用setConfigLocations方法会将创建容器时传入的配置文件路径设置给容器的成员变量,该方法中会完成占位符的替换。构造方法源码如下:

// 核心构造函数,设置此应用上下文的配置文件的位置,并判断是否自动刷新上下文
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {// 将用父类的构造方法,设置父容器super(parent);//设置应用上下文的配置文件的位置,将配置文件的路径存放到configLocations字符串数组中setConfigLocations(configLocations);// 如果刷新表示为true,则会调用refresh()方法加载spring容器if (refresh) {refresh();}
}

  setConfigLocations会解析字符串中的占位符,源码如下:

// 将配置文件的路径放到configLocations 字符串数组中
public void setConfigLocations(@Nullable String... locations) {if (locations != null) {Assert.noNullElements(locations, "Config locations must not be null");// 设置了几个配置文件,就创一个多长的字符串数组,用来存放配置文件的路径this.configLocations = new String[locations.length];for (int i = 0; i < locations.length; i++) {//解析路径,将解析的路径存放到字符串数组中this.configLocations[i] = resolvePath(locations[i]).trim();}}else {this.configLocations = null;}
}

Spring解析占位符

  Spring解析占位符时,需要继续Spring的环境信息进行解析,因此会调用getEnvironment()获取环境信息,然后调用resolveRequiredPlaceholders方法解析字符串。

// 解析给定的路径,必要时用相应的环境属性值替换占位符。应用于配置位置。
protected String resolvePath(String path) {// 获取环境,解决所需的占位符return getEnvironment().resolveRequiredPlaceholders(path);
}

Spring创建标准环境StandardEnvironment

  获取环境信息时,会判断当前环境对象是否为null,如果不为null,直接返回当前对象,如果为null,创建一个环境对象并赋值给成员变量(使用了设计模式中的单例模式,懒汉模式),最后返回环境对象,源码如下:

// 获取spring的环境信息,如果没有指定,获取到的时默认的环境
@Override
public ConfigurableEnvironment getEnvironment() {if (this.environment == null) {this.environment = createEnvironment();}return this.environment;
}

Spring创建占位符解析器

  上文中提到创建环境对象会调用createEnvironment方法,该方法中会创建StandardEnvironment标准环境对象,进而会调用父类AbstractEnvironment的无参构造方法,进而对调用以下代码:

// 使用了模板方法设计模式。
// 给成员变量赋值,并调用子类重写的方法,对propertySources进行操作。
protected AbstractEnvironment(MutablePropertySources propertySources) {// 给全局变量 可变属性源 赋值this.propertySources = propertySources;// 创建属性解析器:PropertySourcesPropertyResolver 属性源属性解析器this.propertyResolver = createPropertyResolver(propertySources);// 自定义属性源,此处回调子类重写的方法。子类通过重写该方法可以操作propertySources。spring标准环境StandardEnvironment重写了该方法customizePropertySources(propertySources);
}

  上文方法会调用createPropertyResolver方法创建属性源属性解析器,源码如下:

// 在创建环境时,需要创建属性解析器
protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {return new PropertySourcesPropertyResolver(propertySources);
}

Spring创建占位符助手

  上文中提到在使用getEnvironment方法获取到StandardEnvironment环境信息后会调用resolveRequiredPlaceholders方法解析占位符(StandardEnvironment类没有重写父类AbstractEnvironment中的resolveRequiredPlaceholders方法,因此调用的时AbstractEnvironment类中的方法),此方法中会调用解析器的resolveRequiredPlaceholders方法解析占位符,代码如下:

// 解析所需占位符
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {return this.propertyResolver.resolveRequiredPlaceholders(text);
}

  在上述方法中调用解析器的resolveRequiredPlaceholders解析占位符。调用的是PropertySourcesPropertyResolver类中的resolveRequiredPlaceholders方法(继承自AbstractPropertyResolver),代码如下:

// 解析占位符
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {if (this.strictHelper == null) {// 创建占位符助手this.strictHelper = createPlaceholderHelper(false);}// 解析占位符return doResolvePlaceholders(text, this.strictHelper);
}

  解析占位符时,会先创建占位符助手,代码如下:

// 创建占位符助手
private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix,this.valueSeparator, ignoreUnresolvablePlaceholders);
}

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

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

相关文章

pip升级超时问题

今天升级pip超时提示 &#xff1a;failed with error code 1 in None&#xff0c;问题原因是pip版本过低&#xff0c;需要升级pip。 升级pip命令&#xff08;绝逼不会超时了&#xff09; python -m pip install --upgrade pip -i http://pypi.douban.com/simple --trusted-ho…

通过Idea部署Tomcat服务器(详细图文教学)

1.在idea中创建项目 有maven构建工具就创建maven&#xff0c;没有就正常创建一个普通的java程序 创建普通java项目 2.添加框架 3.配置 Tomcat 注意&#xff1a;创建web项目后我们需要配置tomcat才能运行&#xff0c;下面我们来进行配置。 4.添加部署 回到服务器 5.完善配置 6…

第28天-Kubernetes架构,集群部署,Ingress,项目部署,Dashboard

1.K8S集群部署 1.1.k8s快速入门 1.1.1.简介 Kubernetes简称k8s&#xff0c;是用于自动部署&#xff0c;扩展和管理容器化应用程序的开源系统。 中文官网&#xff1a;https://kubernetes.io/zh/中文社区&#xff1a;https://www.kubernetes.org.cn/官方文档&#xff1a;https…

Flask 是什么?Flask框架详解及实践指南

Flask 是一个轻量级的 Python Web 框架&#xff0c;它被广泛用于构建 Web 应用程序和 API。Flask 简单易用&#xff0c;具有灵活性和可扩展性&#xff0c;是许多开发者喜欢用其构建项目的原因。本文将介绍 Flask 是什么以及如何使用它来构建 Web 应用程序&#xff0c;同时提供一…

redis原理 3:未雨绸缪 —— 持久化

redis原理 3&#xff1a;未雨绸缪 —— 持久化 Redis 的数据全部在内存里&#xff0c;如果突然宕机&#xff0c;数据就会全部丢失&#xff0c;因此必须有一种机制来保证 Redis 的数据不会因为故障而丢失&#xff0c;这种机制就是 Redis 的持久化机制。 Redis 的持久化机制有两种…

docker容器内的django启动celery任务队列

问题1&#xff1a; celery任务队列一般要使用redis&#xff0c;但是容器内的django要访问本机的redis是十分麻烦的 解决2&#xff1a; 在容器内安装redis&#xff0c;或者单独启动一个redis的容器&#xff0c;我是单独启动一个redis容器 安装redis镜像docker pull redis启动…

【Ansible】Ansible自动化运维工具之playbook剧本搭建LNMP架构

LNMP 一、playbooks 分布式部署 LNMP1. 环境配置2. 安装 ansble3. 安装 nginx3.1 准备 nginx 相关文件3.2 编写 lnmp.yaml 的 nginx 部分3.3 测试 nginx4. 安装 mysql4.1 准备 mysql 相关文件4.2 编写 lnmp.yaml 的 mysql 部分4.3 测试 mysql5. 安装 php5.1 编写 lnmp.yaml 的 …

gradio创建机器学习的好工具 基本使用和示例

1.gradio介绍 Gradio: 用Python构建机器学习网页APP Gradio是一个开源的Python库,用于构建演示机器学习或数据科学,以及web应用程序。 使用Gradio,您可以基于您的机器学习模型或数据科学工作流快速创建一个漂亮的用户界面,让用户可以”尝试“拖放他们自己的图像、粘贴文本…

【云原生持续交付和自动化测试】5.2 自动化测试和集成测试

往期回顾&#xff1a; 第一章&#xff1a;【云原生概念和技术】 第二章&#xff1a;【容器化应用程序设计和开发】 第三章&#xff1a;【基于容器的部署、管理和扩展】 第四章&#xff1a;【微服务架构设计和实现】 第五章&#xff1a;【5.1 自动化构建和打包容器镜像】 5…

【深度学习_TensorFlow】感知机、全连接层、神经网络

写在前面 感知机、全连接层、神经网络是什么意思&#xff1f; 感知机&#xff1a; 是最简单的神经网络结构&#xff0c;可以对线性可分的数据进行分类。 全连接层&#xff1a; 是神经网络中的一种层结构&#xff0c;每个神经元与上一层的所有神经元相连接,实现全连接。 神经…

HTML 基础标签

前言 当今互联网时代&#xff0c;网页是我们获取信息、交流和展示自己的重要渠道之一。而HTML&#xff08;超文本标记语言&#xff09;作为构建网页的基础&#xff0c;学习掌握HTML标签成为了必不可少的技能。 标题标签 <h1>~<h6>&#xff1a;这是用来定义标题的…

Python:Spider爬虫工程化入门到进阶(2)使用Spider Admin Pro管理scrapy爬虫项目

Python&#xff1a;Spider爬虫工程化入门到进阶系列: Python&#xff1a;Spider爬虫工程化入门到进阶&#xff08;1&#xff09;创建Scrapy爬虫项目Python&#xff1a;Spider爬虫工程化入门到进阶&#xff08;2&#xff09;使用Spider Admin Pro管理scrapy爬虫项目 目录 1、使…

使用Golang实现一套流程可配置,适用于广告、推荐系统的业务性框架——简单应用

在诸如广告、推荐等系统中&#xff0c;我们往往会涉及过滤、召回和排序等过程。随着系统业务变得复杂&#xff0c;代码的耦合和交错会让项目跌入难以维护的深渊。于是模块化设计是复杂系统的必备基础。这篇文章介绍的业务框架脱胎于线上多人协作开发、高并发的竞价广告系统&…

android kernel移植5-RK3568

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言1.添加开发板默认配置文件前言 前面我们已经学会了移植uboot,其实就是把瑞芯微的关于uboot的一些文件的名字和编译指定的文件改为自己定义的问价和名字,那么接下来的Android kernel其实也是…

C语言笔记6

关于microsoft visual 的学习笔记 CtrlF5就是启动编译程序 先CtrlA进行全选&#xff0c;然后AitF8就自动的调节代码的格式 #include <stdio.h> #include <stdlib.h> int main() {//system启动程序(在一个程序中启动另外一个程序)//如果程序环境变量中找不到程序&am…

webpack源码简版

Compiler.js:负责整个编译过程的控制和管理&#xff0c;包含compiler构造函数&#xff0c;在构造函数中获取webpack.config.js的出口、入口、参数等Bundler.js:引入webpack.config.js和compiler.js&#xff0c;创建compiler实例化对象并传入options。拿到webpack配置参数后开始…

Java自定义校验注解实现List、set集合字段唯一性校验

文章目录 一&#xff1a; 使用场景二&#xff1a; 定义FieldUniqueValid注解2.1 FieldUniqueValid2.2 注解说明2.3 Constraint 注解介绍2.4 FieldUniqueValid注解使用 三&#xff1a;自定义FieldUniqueValidator校验类3.1 实现ConstraintValidator3.2 重写initialize方法3.3 重…

STM32(HAL)多串口进行重定向(printf函数发送数据)

目录 1、简介 2.1 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 串口外设配置 2.3 项目生成 3、KEIL端程序整合 4、效果测试 1、简介 在HAL库中&#xff0c;常用的printf函数是无法使用的。本文通过重映射实现在HAL库多个串口可进行类似printf函数的操作。 2.1 基础配置 2.…

【c++】VSCode配置 c++ 环境(重新制作)

上一篇帖子【c】VSCode配置 c 环境&#xff08;小白教程&#xff09;_vscode配置c/c环境_StudyWinter的博客-CSDN博客 大火&#xff0c;但是依旧有很多小伙伴反应没有配好环境&#xff0c;今天打算重新写一个教程&#xff0c;希望对大家有帮助。 1 MinGW下载安装 在CSDN上传了…