专题四:Spring源码初始化环境与BeanFactory

news2025/1/19 2:34:52

上文我们通过new ClassPathXmlApplicationContext("applicationContext.xml");这段代码看了下Spring是如何将Xml里面内容注入到Java对象中,并通过context.getBean("jmUser");方式获得了一个对象实例,而避开使用new 来耦合。今天我们就来看看Spring是如何做到的呢?

上图是AbstractApplicationContext的类图,dedug跟踪这段代码

 new ClassPathXmlApplicationContext("applicationContext.xml");

ClassPathXmlApplicationContext构造方法

/**
	 * 根据xml路径,创建一个ClassPathXmlApplicationContext实例
	 * Create a new ClassPathXmlApplicationContext with the given parent,
	 * loading the definitions from the given XML files.
	 * @param configLocations array of resource locations
	 * @param refresh whether to automatically refresh the context,
	 * loading all bean definitions and creating all singletons.
	 * Alternatively, call refresh manually after further configuring the context.
	 * @param parent the parent context
	 * @throws BeansException if context creation failed
	 * @see #refresh()
	 */
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		// 调用父类构造方法,主要是初始化环境变量相关信息,核心代码在 AbstractApplicationContext 类中
		super(parent);
		// 设置配置文件的位置 ApplicationContext的实现可能会使用默认的配置文件位置。
		setConfigLocations(configLocations);
		// 默认构造true
		if (refresh) {
			// 进入核心方法
			refresh();
		}
	}

1、初始化环境变量相关信息

发现最终进入

	/**
	 * Create a new AbstractApplicationContext with no parent.
	 * 创建一个没有父容器的AbstractApplicationContext的实例
	 */
	public AbstractApplicationContext() {
		//  返回一个 PathMatchingResourcePatternResolver(this)实例
		this.resourcePatternResolver = getResourcePatternResolver();
	}

	/**
	 * Create a new AbstractApplicationContext with the given parent context.
	 * @param parent the parent context
	 */
	public AbstractApplicationContext(@Nullable ApplicationContext parent) {
		this();
		// 将父容器复制给成员变量 parent,如果parent不为空且属于ConfigurableEnvironment类型则合并环境
		setParent(parent);
	}

2、设置配置文件的位置

/**
	 * Set the config locations for this application context.
	 * <p>If not set, the implementation may use a default as appropriate.
	 * 配置了配置文件的位置
	 * 如果未设置配置位置,某些ApplicationContext的实现可能会使用默认的配置文件位置。
	 * 例如,ClassPathXmlApplicationContext如果没有指定配置位置,会尝试查找类路径下的applicationContext.xml文件。
	 */
	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++) {
//				getEnvironment().resolveRequiredPlaceholders(path),从路径中解析展位福${}参数
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}
	}


	/**
	 * Resolve the given path, replacing placeholders with corresponding
	 * environment property values if necessary. Applied to config locations.
	 * @param path the original file path
	 * @return the resolved file path
	 * @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)
	 */
	protected String resolvePath(String path) {
		return getEnvironment().resolveRequiredPlaceholders(path);
	}

	public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
		return this.propertyResolver.resolveRequiredPlaceholders(text);
	}

3、进入refresh方法

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing. 1、初始化上下文信息
			prepareRefresh();
			// Tell the subclass to refresh the internal bean factory. 2、解析类Xml、初始化BeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// Prepare the bean factory for use in this context. 	3、准备BeanFactory内容
			prepareBeanFactory(beanFactory);
			try {
				// Allows post-processing of the bean factory in context subclasses. 4、扩展点加一:空实现,主要用于处理特殊Bean的后置处理器
				postProcessBeanFactory(beanFactory);
				// Invoke factory processors registered as beans in the context. 	5、spring bean容器的后置处理器
				invokeBeanFactoryPostProcessors(beanFactory);
				// Register bean processors that intercept bean creation. 	6、注册bean的后置处理器
				registerBeanPostProcessors(beanFactory);
				// Initialize message source for this context.	7、初始化消息源
				initMessageSource();
				// Initialize event multicaster for this context.	8、初始化事件广播器
				initApplicationEventMulticaster();
				// Initialize other special beans in specific context subclasses. 9、扩展点加一:空实现;主要是在实例化之前做些bean初始化扩展
				onRefresh();
				// Check for listener beans and register them.	10、初始化监听器
				registerListeners();
				// Instantiate all remaining (non-lazy-init) singletons.	11、实例化:非兰加载Bean
				finishBeanFactoryInitialization(beanFactory);
				// Last step: publish corresponding event.	 12、发布相应的事件通知
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

整个流程可以分为以下几个主要步骤:

  1. 初始化上下文环境信息。
  2. 解析XML配置文件,创建并初始化BeanFactory
  3. 设置BeanFactory的类加载器,注册一些默认的环境Bean。
  4. 提供扩展点用于对BeanFactory进行进一步的定制。
  5. 调用BeanFactory的后置处理器。
  6. 注册Bean的后置处理器。
  7. 初始化消息源,用于国际化支持。
  8. 初始化事件广播器,用于发布事件。
  9. 提供扩展点用于在刷新上下文时做一些特殊的初始化。
  10. 检查并注册监听器Bean。
  11. 实例化所有剩余的单例Bean(非懒加载)。
  12. 发布相应的事件通知,表示上下文刷新完成。

步骤概览

1. prepareRefresh()
prepareRefresh();

prepareRefresh()方法用于初始化上下文环境信息,包括设置启动时间、活动状态等基本属性。它确保在刷新过程中,应用上下文处于正确的状态。

2. obtainFreshBeanFactory()
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

该方法解析XML配置文件,创建并初始化BeanFactory,并载入Bean定义。它是Spring应用上下文初始化的关键步骤之一。

3. prepareBeanFactory(beanFactory)
prepareBeanFactory(beanFactory);

此步骤设置BeanFactory的类加载器,并注册一些默认的环境Bean,如类加载器、表达式解析器等。它确保BeanFactory在上下文中能够正确工作。

4. postProcessBeanFactory(beanFactory)
postProcessBeanFactory(beanFactory);

这是一个扩展点,通常为空实现。开发者可以在子类中重写该方法,对BeanFactory进行进一步的定制,如添加额外的Bean定义或修改现有的Bean定义。

5. invokeBeanFactoryPostProcessors(beanFactory)
invokeBeanFactoryPostProcessors(beanFactory);

该方法调用BeanFactory的后置处理器,这些处理器可以在Bean实例化之前对Bean定义进行修改或增加新的Bean定义。

6. registerBeanPostProcessors(beanFactory)
registerBeanPostProcessors(beanFactory);

在此步骤中,Spring注册Bean的后置处理器,这些处理器会在Bean的创建过程中拦截并进行处理,如执行依赖注入和初始化回调等。

7. initMessageSource()
initMessageSource();

该方法初始化消息源,用于支持国际化(i18n)。它允许应用程序根据用户的语言环境显示不同的消息。

8. initApplicationEventMulticaster()
initApplicationEventMulticaster();

Spring使用事件广播器来发布和监听应用程序事件。该方法初始化事件广播器,确保事件能够在应用上下文中正确传播。

9. onRefresh()
onRefresh();

这是另一个扩展点,通常为空实现。开发者可以在子类中重写该方法,在刷新上下文时执行一些特殊的初始化操作。

10. registerListeners()
registerListeners();

该方法检查并注册监听器Bean,用于监听和处理应用程序事件。

11. finishBeanFactoryInitialization(beanFactory)
finishBeanFactoryInitialization(beanFactory);

此步骤实例化所有剩余的单例Bean(非懒加载)。它确保所有Bean都已准备就绪,可以在应用程序中使用。

12. finishRefresh()
finishRefresh();

最后,Spring发布相应的事件通知,表示上下文刷新已完成。此步骤通常包括发布ContextRefreshedEvent事件,通知所有监听器上下文已刷新。

总结

本章主要通过断点源码,一步步跟踪到refresh方法,然后整体跟踪了refresh的具体步骤,每一步大概干了什么内容,后面我们将一个一个方法深入讨论,具体做了什么?预留了什么扩展点。我们在开发中怎么去使用这些扩展点。以及后面SpringBoot和SpringCloud是怎样利用这些扩展点给我么提供开箱即用的功能的。

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

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

相关文章

Houdini速通VOP强化训练上部

Houdini 速通 VOP 强化训练上部是一门针对 Houdini 中 VOP&#xff08;Vector Operation Language&#xff09;的强化训练课程。本课程深入探讨了 Houdini 中 VOP 的核心概念和高级技术&#xff0c;通过实际案例和项目实战&#xff0c;帮助学员快速掌握 VOP 的使用技巧和编程方…

SpringBoot Task 定时任务

springboot中使用Task定时任务非常简单 springboot 中自带的都有注解不需要引入依赖 第一步&#xff1a;在启动类上添加启用定时任务注解 EnableScheduling //开启任务调度 第二步&#xff1a;创建一个springboot组件用于定时任务管理 package cn.lsy.api.Task;import cn.ls…

【Unity实战】在RHEL 9上安装UnityHub

一般来说&#xff0c;Unity编辑器的安装&#xff0c;官方已经给出了安装教程。 但是这个忽略了RHEL 9的一个特性&#xff1a;默认的加解密策略已经不支持SHA1了&#xff0c;你会在执行yum install unityhub那里出现如下报错&#xff1a; [shepherdlocalhost ~]$ sudo yum inst…

[C++][设计模式][备忘录模式]详细讲解

目录 1.动机2.模式定义3.要点总结4.代码感受 1.动机 在软件构建过程中&#xff0c;某些对象的状态转换过程中&#xff0c;可能由于某中需要&#xff0c;要求程序能够回溯到对象之前处于某个点的状态。 如果使用一些公开接口来让其他对象得到对象的状态&#xff0c;便会暴露对象…

66、基于长短期记忆 (LSTM) 网络对序列数据进行分类

1、基于长短期记忆 (LSTM) 网络对序列数据进行分类的原理及流程 基于长短期记忆&#xff08;LSTM&#xff09;网络对序列数据进行分类是一种常见的深度学习任务&#xff0c;适用于处理具有时间或序列关系的数据。下面是在Matlab中使用LSTM网络对序列数据进行分类的基本原理和流…

TomCat小型服务器安装

一、安装步骤 Tomcat官方站点&#xff1a; http://tomcat.apache.org 1、进入官方网站后获取安装包&#xff1a; &#x1f920;tar.gz文件是Linux操作系统下的安装版本 &#x1f920;zip文件是Windows系统下的压缩版本 2、解压安装 解压到自己的文件夹中 3、安装JDK 设置环…

Go源码--context包

简介 Context 是go语言比较重要的且也是比较复杂的一个结构体&#xff0c;Context主要有两种功能: 取消信号&#xff1a;包括直接取消&#xff08;涉及的结构体&#xff1a;cancelCtx ; 涉及函数&#xff1a;WithCancel&#xff09;和携带截止日期的取消&#xff08;涉及结构…

功能强大的声音模拟合成软件Togu Audio Line TAL-Mod 1.9.7

Togu Audio Line TAL一个虚拟模拟合成器,具有卓越的声音和几乎无限的调制能力。其特殊的振荡器模型能够创建广泛的声音,从经典的单声道到丰富的立体声引线、效果器和焊盘。路由可以使用虚拟跳线电缆来完成。只需连接调制输出以达到调制的目的。之后,您可以调整调制强度。您不…

dB分贝入门

主要参考资料&#xff1a; dB&#xff08;分贝&#xff09;定义及其应用: https://blog.csdn.net/u014162133/article/details/110388145 目录 dB的应用一、声音的大小二、信号强度三、增益 dB的应用 一、声音的大小 在日常生活中&#xff0c;住宅小区告知牌上面标示噪音要低…

Excel表格转Tex工具推荐

为了制作符合 SCI 论文要求的表格&#xff0c;直接用 LaTeX 编写通常比较复杂。我们可以先在 Excel 中绘制好所需的表格&#xff08;最好加上边框&#xff09;。最近我发现了一个非常好用的 Excel 转 LaTeX 工具&#xff0c;能够让 LaTeX 表格的编写变得非常方便。 工具&#…

数据资产治理的智能化探索:结合云计算、大数据、人工智能等先进技术,探讨数据资产治理的智能化方法,为企业提供可靠、高效的数据资产解决方案,助力企业提升竞争力

一、引言 在信息化时代&#xff0c;数据已成为企业最重要的资产之一。随着云计算、大数据、人工智能等先进技术的飞速发展&#xff0c;数据资产治理面临着前所未有的机遇与挑战。本文旨在探讨如何结合这些先进技术&#xff0c;实现数据资产治理的智能化&#xff0c;为企业提供…

X科网js逆向分析

登录抓包之后发现pwd字眼&#xff0c;直接搜索即可 通过$.md5(pwd)之后得到的加密结果就是我们的pwd参数 他说是md5我们不妨测试一下&#xff1a; 1&#xff09;测试使用$.md5(1)加密数字1 得到c4ca4&#xff0c;说明就是$.md5()&#xff0c;md5加密 2&#xff09;测试$.md5…

神经网络在机器学习中的应用:手写数字识别

机器学习是人工智能的一个分支&#xff0c;它使计算机能够从数据中学习并做出决策或预测。神经网络作为机器学习的核心算法之一&#xff0c;因其强大的非线性拟合能力而广泛应用于各种领域&#xff0c;包括图像识别、自然语言处理和游戏等。本文将介绍如何使用神经网络对MNIST数…

独一无二的设计模式——单例模式(Java实现)

1. 引言 亲爱的读者们&#xff0c;欢迎来到我们的设计模式专题&#xff0c;今天的讲解的设计模式&#xff0c;还是单例模式哦&#xff01;上次讲解的单例模式是基于Python实现&#xff08;独一无二的设计模式——单例模式&#xff08;python实现&#xff09;&#xff09;的&am…

【数据结构】C语言实现二叉树的基本操作——二叉树的层次遍历、求深度、求结点数……

C语言实现二叉树的基本操作 导读一、层次遍历1.1 算法思路1.2 算法实现1.2.1 存储结构的选择1.2.2 函数的三要素1.2.3 函数的实现 1.3 小结 二、求二叉树的深度2.1 层序遍历2.2 分治思想——递归 三、 求二叉树的结点数3.1 求二叉树的结点总数3.1.1 层序遍历3.1.2 分治思想——…

SpringBoot | 使用jwt令牌实现登录认证,使用Md5加密实现注册

对于登录认证中的令牌&#xff0c;其实就是一段字符串&#xff0c;那为什么要那么麻烦去用jwt令牌&#xff1f;其实对于登录这个业务&#xff0c;在平常我们实现这个功能时&#xff0c;可能大部分都是通过比对用户名和密码&#xff0c;只要正确&#xff0c;就登录成功&#xff…

【Python实战因果推断】9_元学习器4

目录 Double/Debiased Machine Learning Double/Debiased Machine Learning Double/Debiased ML 或 R-learner 可以看作是 FrischWaugh-Lovell 定理的改进版。其思路非常简单--在构建结果和治疗残差时使用 ML 模型 结果和干预残差&#xff1a; , 预估&#xff0c;预估 由于 …

Python pdfkit wkhtmltopdf html转换pdf 黑体字体乱码

wkhtmltopdf 黑体在html转换pdf时&#xff0c;黑体乱码&#xff0c;分析可能wkhtmltopdf对黑体字体不太兼容&#xff1b; 1.html内容如下 <html> <head> <meta http-equiv"content-type" content"text/html;charsetutf-8"> </head&…

springboot使用测试类报空指针异常

检查了Service注解&#xff0c;还有Autowired注解&#xff0c;还有其他注解&#xff0c;后面放心没能解决问题&#xff0c;最后使用RunWith(SpringRunner.class)解决了问题&#xff01;&#xff01; 真的是✓8了&#xff0c;烦死了这个✓8报错&#xff01;

Android Focused Window的更新

启动App时更新inputInfo/请求焦点窗口流程&#xff1a; App主线程调ViewRootImpl.java的relayoutWindow()&#xff1b;然后调用到Wms的relayoutWindow()&#xff0c;窗口布局流程。焦点窗口的更新&#xff0c;通过WMS#updateFocusedWindowLocked()方法开始&#xff0c;下面从这…