当前位置: 首页 > news >正文

Spring源码学习-Spring流程概述(一)

Spring启动的流程
public class Test {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");Student bean = context.getBean(Student.class);context.close();}
}

调用本类的构造方法

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {// 调用父类构造方法,进行相关的对象创建等操作,包含属性的赋值操作super(parent);//设置应用程序上下文的配置路径setConfigLocations(configLocations);if (refresh) {refresh();}}

这个refresh方法包含了spring的启动核心流程

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing./*** 做容器刷新前的准备工作* 1、设置容器的启动时间* 2、获取Environment对象,并加载当前系统的属性值到Environment对象中* 3、准备监听器和事件的集合对象,默认为空的集合*/prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 创建容器对象:DefaultListableBeanFactory// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// beanFactory的准备工作,对各种属性进行填充prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 调用各种beanFactory处理器invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法registerBeanPostProcessors(beanFactory);// Initialize message source for this context.// 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲initMessageSource();// Initialize event multicaster for this context.// 初始化事件监听多路广播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 留给子类来初始化其他的beanonRefresh();// Check for listener beans and register them.// 在所有注册的bean中查找listener bean,注册到消息广播器中registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 初始化剩下的单实例(非懒加载的)finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人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.// 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件beandestroyBeans();// Reset 'active' flag.// 重置active标志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();}}}

下面挨个讲解上面的13个方法
1.prepareRefresh ,容器启动之前的准备工作

  • 设置容器的启动时间
  • 获取Environment对象,并加载当前系统的属性值到Environment对象中
  • 准备监听器和事件的集合对象,默认为空的集合

protected void prepareRefresh() {// Switch to active.// 设置容器启动的时间this.startupDate = System.currentTimeMillis();// 容器的关闭标志位this.closed.set(false);// 容器的激活标志位this.active.set(true);// 记录日志if (logger.isDebugEnabled()) {if (logger.isTraceEnabled()) {logger.trace("Refreshing " + this);}else {logger.debug("Refreshing " + getDisplayName());}}// Initialize any placeholder property sources in the context environment.// 留给子类覆盖,初始化属性资源initPropertySources();// Validate that all properties marked as required are resolvable:// see ConfigurablePropertyResolver#setRequiredProperties// 创建并获取环境对象,验证需要的属性文件是否都已经放入环境中getEnvironment().validateRequiredProperties();// Store pre-refresh ApplicationListeners...// 判断刷新前的应用程序监听器集合是否为空,如果为空,则将监听器添加到此集合中if (this.earlyApplicationListeners == null) {this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);}else {// Reset local application listeners to pre-refresh state.// 如果不等于空,则清空集合元素对象this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);}// Allow for the collection of early ApplicationEvents,// to be published once the multicaster is available...// 创建刷新前的监听事件集合this.earlyApplicationEvents = new LinkedHashSet<>();}

2.obtainFreshBeanFactory 创建容器对象:DefaultListableBeanFactory;加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中refreshBeanFactory();// 返回当前实体的beanFactory属性return getBeanFactory();}
protected final void refreshBeanFactory() throws BeansException {// 如果存在beanFactory,则销毁beanFactoryif (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建DefaultListableBeanFactory对象DefaultListableBeanFactory beanFactory = createBeanFactory();// 为了序列化指定id,可以从id反序列化到beanFactory对象beanFactory.setSerializationId(getId());// 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖customizeBeanFactory(beanFactory);// 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析loadBeanDefinitions(beanFactory);this.beanFactory = beanFactory;}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}

这里创建了DefaultListableBeanFactory容器对象,他能枚举出所有的bean实例

	protected DefaultListableBeanFactory createBeanFactory() {return new DefaultListableBeanFactory(getInternalParentBeanFactory());}

基于xml形式的bean定义读取

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.// 创建一个xml的beanDefinitionReader,并通过回调设置到beanFactory中XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.// 给reader对象设置环境对象beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.//  初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证initBeanDefinitionReader(beanDefinitionReader);// 开始完成beanDefinition的加载loadBeanDefinitions(beanDefinitionReader);}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {// 以Resource的方式获得配置文件的资源位置Resource[] configResources = getConfigResources();if (configResources != null) {reader.loadBeanDefinitions(configResources);}// 以String的形式获得配置文件的位置String[] configLocations = getConfigLocations();if (configLocations != null) {reader.loadBeanDefinitions(configLocations);}}

类图如下
在这里插入图片描述
3.prepareBeanFactory,beanFactory的准备工作,对各种属性进行填充

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.// 设置beanFactory的classloader为当前context的classloaderbeanFactory.setBeanClassLoader(getClassLoader());// 设置beanfactory的表达式语言处理器beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));// 为beanFactory增加一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具类beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.// 添加beanPostProcessor,ApplicationContextAwareProcessor此类用来完成某些Aware对象的注入beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 设置要忽略自动装配的接口,很多同学理解不了为什么此处要对这些接口进行忽略,原因非常简单,这些接口的实现是由容器通过set方法进行注入的,// 所以在使用autowire进行注入的时候需要将这些接口进行忽略beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);// BeanFactory interface not registered as resolvable type in a plain factory.// MessageSource registered (and found for autowiring) as a bean.// 设置几个自动装配的特殊规则,当在进行ioc初始化的如果有多个实现,那么就使用指定的对象进行注入beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// Register early post-processor for detecting inner beans as ApplicationListeners.// 注册BPPbeanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// Detect a LoadTimeWeaver and prepare for weaving, if found.// 增加对AspectJ的支持,在java中织入分为三种方式,分为编译器织入,类加载器织入,运行期织入,编译器织入是指在java编译器,采用特殊的编译器,将切面织入到java类中,// 而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面,运行期织入则是采用cglib和jdk进行切面的织入// aspectj提供了两种织入方式,第一种是通过特殊编译器,在编译器,将aspectj语言编写的切面类织入到java类中,第二种是类加载期织入,就是下面的load time weaving,此处后续讲if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}// Register default environment beans.// 注册默认的系统环境bean到一级缓存中if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());}if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());}if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());}}

相关文章:

Spring源码学习-Spring流程概述(一)

Spring启动的流程 public class Test {public static void main(String[] args) {ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext("applicationContext.xml");Student bean context.getBean(Student.class);context.close();} }调用…...

Figma怎么设置中文,Figma有中文版吗?

不是很多人不想用 Figma&#xff0c;真是因为纯英文界面而头疼。这就是为什么有人会到处搜索 Figma 如何设置中文这样的问题。 然后我们直接快刀斩乱麻&#xff0c;Figma 没有中文版&#xff0c;但是我们还有其他的方法&#xff1a;例如&#xff0c; Figma 添加一个插件来解决…...

智慧文旅一机游:科技与文化的完美结合,引领智慧文旅新潮流,智慧旅游未来已来

一、科技与文化的完美结合&#xff1a;智慧文旅一机游的核心理念 智慧文旅一机游&#xff0c;是科技与文化相融合的产物&#xff0c;它不仅代表着旅游行业的创新与发展&#xff0c;更是一种文化与科技完美结合的生活方式。一机游的核心理念在于通过先进的科技手段&#xff0c;提…...

多维时序 | Matlab实现CNN-LSTM-Mutilhead-Attention卷积长短期记忆神经网络融合多头注意力机制多变量时间序列预测

多维时序 | Matlab实现CNN-LSTM-Mutilhead-Attention卷积长短期记忆神经网络融合多头注意力机制多变量时间序列预测 目录 多维时序 | Matlab实现CNN-LSTM-Mutilhead-Attention卷积长短期记忆神经网络融合多头注意力机制多变量时间序列预测效果一览基本介绍程序设计参考资料 效果…...

软件工程实验报告(完整)

博主介绍&#xff1a;✌全网粉丝喜爱、前后端领域优质创作者、本质互联网精神、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战✌有需要可以联系作者我哦&#xff01; &#x1f345;附上相关C语言版源码讲解&#x1f345; &#x1f44…...

Java零基础学习20:集合的练习

编写博客目的&#xff1a;本系列博客均根据B站黑马程序员系列视频学习和编写目的在于记录自己的学习点滴&#xff0c;方便后续回忆和查找相关知识点&#xff0c;不足之处恳请各位有缘的朋友指正。 一、查找id对应的集合索引 package www.itheima;import java.util.ArrayList;…...

【latex】在Overleaf的IEEE会议模板中,快速插入参考文献

【LaTeX】在Overleaf的IEEE会议模板中&#xff0c;快速插入参考文献 写在最前面第一步&#xff1a;在文献检索网站导出引用文献的bib文件第二步&#xff1a;编辑overleaf模版方法二&#xff1a;EduBirdie生成参考文献&#xff08;补充&#xff09;使用LaTeX在Overleaf的IEEE会议…...

java反射之Field用法(获取对象的字段名和属性值)

一、概述 Field是一个类,位于java.lang.reflect包下。在Java反射中Field类描述的是类的属性信息&#xff0c;功能包括&#xff1a; 获取当前对象的成员变量的类型 对成员变量重新设值 二、如何获取Field类对象 getField(String name)&#xff1a; 获取类特定的方法&#xff0c…...

Java Web(三)--CSS

介绍 为什么需要&#xff1a; 在没有 CSS 之前&#xff0c;想要修改 HTML 元素的样式需要为每个 HTML 元素单独定义样式属性&#xff0c;费心费力&#xff1b;CSS 可以让 html 元素(内容) 样式(CSS)分离&#xff0c;提高web 开发的工作效率(针对前端开发)&#xff0c;从而…...

天津大数据培训班推荐,数据分析过程的常见错误

大数据”是近年来IT行业的热词&#xff0c;目前已经广泛应用在各个行业。大数据&#xff0c;又称海量信息&#xff0c;特点是数据量大、种类多、实时性强、数据蕴藏的价值大。大数据是对大量、动态、能持续的数据&#xff0c;通过运用分析、挖掘和整理&#xff0c;实现数据信息…...

【笔记】Helm-3 主题-17 弃用的Kubernetes API

弃用的Kubernetes API Kubernetes是一个API驱动系统&#xff0c;且API会随着时间的推移而变化&#xff0c;以反映对问题理解的不断推移。这是系统及API的普遍做法。API推移的一个重要部分是良好的弃用策略和通知用户更改API是如何实现的。换句话说&#xff0c;您的API使用者需要…...

麒麟系统—— openKylin 安装 java

麒麟系统—— openKylin 安装 java JDK 一、准备工作1. 确保麒麟系统 openKylin 已经安装完毕。2. 了解 java JDK 的版本信息&#xff0c;以便下载合适的安装包。 二、安装 java JDK3. 将下载好的 java JDK 安装包解压到指定目录。4. 配置环境5. 验证安装结果 本文将分享如何在…...

HTML学习笔记——07:其他嵌入技术

除了将图像、视频和音频嵌入到网页上&#xff0c;还能让你在网页中嵌入各种内容类型的元素&#xff1a;<iframe>, <embed> 和 <object> 元素。 <iframe>用于嵌入其他网页&#xff0c;另外两个元素则允许你嵌入 PDF&#xff0c;SVG&#xff0c;甚至 Fl…...

【UE】在控件蓝图中通过时间轴控制材质参数变化

效果 步骤 1. 新建一个控件蓝图和一个材质 2. 打开材质&#xff0c;设置材质域为用户界面&#xff0c;混合模式设置为“半透明” 在材质图表中添加两个参数来控制材质的颜色和不透明度 3. 对材质创建材质实例 4. 打开控件蓝图&#xff0c;在画布面板中添加一个图像控件 将刚…...

linux C语言socket函数send

在Linux中&#xff0c;使用C语言进行网络编程时&#xff0c;send函数是用于发送数据到已连接的套接字的重要函数之一。它通常用于TCP连接&#xff0c;但也可以用于UDP&#xff08;尽管对于UDP&#xff0c;通常更推荐使用sendto&#xff0c;因为它允许你指定目标地址和端口&…...

Django(八)

1. 管理员操作 1.1 添加 from django.shortcuts import render, redirectfrom app01 import models from app01.utils.pagination import Paginationfrom django import forms from django.core.exceptions import ValidationError from app01.utils.bootstrap import BootStr…...

上海计算机学会12月月赛 丙组题解

上海计算机学会 12 月月赛 丙组题解涉及知识点&#xff1a;数学、字符串、模拟、裴蜀定理、宽度优先搜索、动态规划 比赛链接&#xff1a;https://iai.sh.cn/contest/58 第一题&#xff1a;T1数砖数 标签&#xff1a;数学题意&#xff1a;给定一种 2 2 2x 2 2 2的瓷砖&#…...

nextjs中beforePopState使用

在某些情况下&#xff0c;希望监听popstate并在路由器对其进行操作之前执行某些操作。可以使用beforePopState。 在Next.js中&#xff0c;beforePopState是一个可选的生命周期函数&#xff0c;用于在浏览器的历史记录发生更改之前执行一些操作。具体来说&#xff0c;beforePopS…...

【并发编程】活锁

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;并发编程 ⛺️稳重求进&#xff0c;晒太阳 活锁 定义&#xff1a;活锁出现在两个线程互相改变对象的结束条件&#xff0c;最后谁也无法结束 代码示例 public class TestLiveLock {stati…...

CSMM和CMMI之间有什么区别?

CSMM&#xff08;软件能力成熟度评估&#xff09;和CMMI&#xff08;能力成熟度模型集成&#xff09;都是软件行业中用于评估和提高企业软件开发过程成熟度的模型。它们之间的主要区别在于起源、定位、适应范围和具体内容。 1. 起源与定位&#xff1a; - CMMI是由美国卡耐基…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...