当前位置: 首页 > 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是由美国卡耐基…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

短视频矩阵系统文案创作功能开发实践,定制化开发

在短视频行业迅猛发展的当下&#xff0c;企业和个人创作者为了扩大影响力、提升传播效果&#xff0c;纷纷采用短视频矩阵运营策略&#xff0c;同时管理多个平台、多个账号的内容发布。然而&#xff0c;频繁的文案创作需求让运营者疲于应对&#xff0c;如何高效产出高质量文案成…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...