spring ioc 容器加载过程 refresh() 方法详解

news2024/11/23 14:50:46

IOC 加载过程 从 new ClassPathXmlApplicationContext开始

ApplicationContext context = new 
ClassPathXmlApplicationContext("classpath:application.xml");

ClassPathXmlApplicationContext类构造方法

public ClassPathXmlApplicationContext(String[] configLocations,
 boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
    super(parent);
    this.setConfigLocations(configLocations);
    if (refresh) {
    	// 执行刷新操作
        this.refresh();
    }
}

核心类和接口

ApplicationContext接口 其实就是一个BeanFactory

作用: 加载配置文件中定义的 bean,并进行管理。

继承了ListableBeanFactory,这个ListableBeanFactory接口可以获取多个bean。
继承了HierarchicalBeanFactory接口,这个接口可以在应用这起多个BeanFactory,然后将多个BeanFactory设置父子关系。
getAutowireCapableBeanFactory() : 用来自动装配Bean

BeanDefinitionReader

配置文件解析器,如将配置文件中的 bean 信息解析成对应的 BeanDefinition 对象。

xml 文件解析使用是就是BeanDefinitionReader 实现类 XmlBeanDefinitionReader。

BeanFactoryPostProcessor

可以修改 Spring 上下文中 BeanDefinition 信息。

BeanFactory

是所有 Bean 容器的根接口,定义了 spring 容器基本方法。如使用 getBean(beanName,Class) 获取对象。

refresh() 详解

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        //1:准备刷新上下文环境。
        prepareRefresh();

        //2:刷新并获取刷新后的 BeanFactory,将配置文件解析为BeanDefinition对象。
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        //3:对 Bean 工厂进行填充属性。
        prepareBeanFactory(beanFactory);

        try {
            //4:beanFactory的后置处理器,空方法,具体由子类实现。
            // 使用设计模式中的模板方法,是一个钩子函数。
            postProcessBeanFactory(beanFactory);

            //5:实例化并调用所有注册的beanFactory后置处理器。
            invokeBeanFactoryPostProcessors(beanFactory);

            //6:加载 BeanPostProcessors。
            registerBeanPostProcessors(beanFactory);

            //7:国际化处理,为上下文实例化并注册一个MessageSource。
            initMessageSource();

            //8:初始化并注册一个事件广播器用来发布事件。
            initApplicationEventMulticaster();

            //9:空方法,由子类实现,使用设计模式中的模板方法,是一个钩子函数。
            onRefresh();

            //10:注册监听器,在所有注册的bean中查找Listener bean,注册到消息广播器中,即向监听器发布事件。
            registerListeners();

            //11:初始化所有的非懒加载的单实例bean(bean的生命周期实例化 属性注入 初始化 完成)
            finishBeanFactoryInitialization(beanFactory);

            //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();
        }
    }
}

图解

在这里插入图片描述

prepareRefresh()

准备刷新上下文环境。

obtainFreshBeanFactory()(重要)

刷新并获取刷新后的 BeanFactory,将配置文件解析为BeanDefinition对象。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //刷新bean工厂()
    refreshBeanFactory();
    //返回之前容器准备工作的时候创建的的bean工厂也就是DefaultListableBeanFactory(很重要)
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}
protected final void refreshBeanFactory() throws IllegalStateException {
    //由于BeanFactory只能刷新一次,多线程情况下可能导致线程安全问题,所有使用cas原子操作来保证
    if (!this.refreshed.compareAndSet(false, true)) {
        throw new IllegalStateException(
                "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    }
    //指定Bean工厂的序列化Id
    this.beanFactory.setSerializationId(getId());
}
prepareBeanFactory()

对 Bean 工厂进行填充属性。

postProcessBeanFactory()

beanFactory的后置处理器,空方法,具体由子类实现。使用设计模式中的模板方法,是一个钩子函数。

invokeBeanFactoryPostProcessors()

实例化并调用所有注册的beanFactory后置处理器。

registerBeanPostProcessors()

加载 BeanPostProcessors。

initMessageSource()

国际化处理,为上下文实例化并注册一个MessageSource。

initApplicationEventMulticaster()

初始化并注册一个事件广播器用来发布事件。

onRefresh()

空方法,由子类实现,使用设计模式中的模板方法,是一个钩子函数。

registerListeners()

注册监听器,在所有注册的bean中查找Listener bean,注册到消息广播器中,即向监听器发布事件。

finishBeanFactoryInitialization()(重要)

初始化所有的非懒加载的单实例bean(bean的生命周期实例化 属性注入 初始化 完成)。

bean实例化 属性注入 初始化

关键方法

AbstractAutowireCapableBeanFactory类的doCreateBean方法
// 其中
createBeanInstance(beanName, mbd, args); // 实例化
populateBean(beanName, mbd, instanceWrapper); // 属性注入
initializeBean(beanName, exposedObject, mbd)  // 初始化
finishRefresh()

最后刷新容器发布刷新事件。

待续…

IOC容器步骤详解

面试详解

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

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

相关文章

自动驾驶融合定位:IMU内参模型及标定

自动驾驶融合定位:IMU内参模型及标定 一、 概述 标定的本质是参数辨识。首先明确哪些参数可辨识,其次弄清怎样辨识。 参数包括陀螺仪和加速度计各自的零偏、标度因数、安装误差。 辨识就比较丰富了,如果让各位先不局限于标定任务&#xf…

数据分析——业务指标分析

业务指标分析 前言一、业务指标分析的定义二、业务问题构建问题构建的要求 三、业务问题的识别在识别问题的阶段对于企业内部收益者的补充 四、竞争者分析竞争者分析的内容竞争者分析目的案例 五、市场机会识别好的市场机会必须满足的条件市场机会案例 六、风险控制数据分析师常…

【Git实战】如何将本地仓库推送至Github(windows版)?

最近使用Go语言开发项目,想寻找位操作相关的工具包。找了一圈没有合适的,因此自己写了一个。又想将其推送到Github上,中间逢山开路,遇水搭桥,终于成功将本地Git仓库和Github进行了关联。现将我的方法公之于众&#xff…

网页html版面分析-- BeauifulSoup(python 文档解析提取)

介绍 BeauifulSoup 是一个可以从HTML或XML 文件中提取数据的python库;它能通过转换器实现惯用的文档导航、查找、修改文档的方式。 BeauifulSoup是一个基于re开发的解析库,可以提供一些强大的解析功能;使用BeauifulSoup 能够提高提取数据的效…

国产最强多模态大模型Step Fun-1V,究竟有多好用?

前言: 2023年是大模型的元年,随着ChatGPT的爆火,将大模型带入了公众的视野 ,国内也随之掀起了百模大战的浪潮。在这股浪潮的推动下,诸多科技公司,乃至大厂都争相推出自己的大模型产品,希望能够…

华为 二层交换机与防火墙连通上网实验

防火墙是一种网络安全设备,用于监控和控制网络流量。它可以帮助防止未经授权的访问,保护网络免受攻击和恶意软件感染。防火墙可以根据预定义的规则过滤流量,例如允许或阻止特定IP地址或端口的流量。它也可以检测和阻止恶意软件、病毒和其他威…

element-plus upload查看图片后不展示press delete to remove?

直接上全局样式就行: :deep(.el-upload-list__item .el-icon--close-tip) {display: none !important; }

灌溉机器人 状压dp

灌溉机器人 题目描述 农田灌溉是一项十分费体力的农活,特别是大型的农田。小明想为农民伯伯们减轻农作负担,最近在研究一款高科技——灌溉机器人。它可以在远程电脑控制下,给农田里的作物进行灌溉。 现在有一片 N 行 M 列的农田。农田的土…

【数据结构】有关环形链表题目的总结

文章目录 引入 - 快慢指针思考 - 快慢指针行走步数进阶 - 寻找环形链表的头 引入 - 快慢指针 141-环形链表 - Leetcode 关于这道题,大家可以利用快慢指针,一个每次走两步,一个每次走一步,只要他们有一次相撞了就代表说这是一个链…

【吃透Java手写】SpringBoot-简易版-源码解析

【吃透Java手写】SpringBoot-简易版-源码解析 1 SpringbootDemo2 准备工作2.1 Springboot-my2.1.1 依赖2.1.2 SpringBootApplication2.1.3 SJBSpringApplication2.1.3.1 run方法 2.2 Springboot-user2.2.1 依赖2.2.2 UserController2.2.3 UserApplication 2.3 分析run方法的逻辑…

13 【PS作图】人物绘画理论-脸型

三庭五眼 三庭:脸的长度比例 (1)发际线到眉毛 (2)眉毛到鼻底 (3)鼻底到下巴 三个部分大致为三等分 五眼:脸的宽度比例 以眼睛长度为单位,把脸的宽度分成五等分&#x…

为什么很多人不推荐你用JWT?

为什么很多人不推荐你用JWT? 如果你经常看一些网上的带你做项目的教程,你就会发现 有很多的项目都用到了JWT。那么他到底安全吗?为什么那么多人不推荐你去使用。这个文章将会从全方面的带你了解JWT 以及他的优缺点。 什么是JWT? 这个是他的官网JSON…

搜索算法系列之四(斐波那契)

以下算法被验证过,如有什么问题或有补充的欢迎留言。 前言 斐波那契数列,又称黄金分割数列,是由意大利数学家(Leonardo Fibonacci)在1202年提出的。这个数列的递推关系是F(0)1,F(1)1,F(n)F(n-…

微搭低代码入门05文件的上传和下载

目录 1 创建数据源2 创建应用3 创建页面4 设置导航功能5 文件上传6 文件下载总结 小程序中,我们通常会有文件的上传和下载的需,在微搭中,文件是存放在云存储中,每一个文件都会有一个唯一的fileid,我们本篇就介绍如何通…

强化学习玩flappy_bird

强化学习玩flappy_bird(代码解析) 游戏地址:https://flappybird.io/ 该游戏的规则是: 点击屏幕则小鸟立即获得向上速度。 不点击屏幕则小鸟受重力加速度影响逐渐掉落。 小鸟碰到地面会死亡,碰到水管会死亡。&#…

vscode连接服务器的docker步骤

进入容器之后,操作方式与本地windows系统操作逻辑一样;容器内部结构都能任意查看和使用,创建文件及编写python脚本都可以直接使用vs code编辑器进行编辑和调试,从而避免使用命令行及vim编辑文件,非常直观且方便~

4. RedHat认证-进程管理

4. RedHat认证-进程管理 1.进程概念 进程就是正在运行中的程序或者命令 每一个进程都是运行的实体,都有自己的地址空间,并占有一定的资源空间 程序消耗的是磁盘资源、进程消耗的是内存和CPU资源 进程会占用四类资源(CPU 、内存、磁盘、网…

python爬虫(一)之 抓取极氪网站汽车文章

极氪汽车文章爬虫 闲来没事,将极氪网站的汽车文章吃干抹尽,全部抓取到本地,还是有点小小的难度。不能抓取太快,太快容易被封禁IP,不过就算被封了问题也不大,大不了重启路由器,然后你的IP里面又…

i.MX 6ULL 裸机 IAR 环境安装

一. IAR 的安装请自行搜索 二. 使用最新版本的 IAR,需要修改 SDK 1. 在 SDK 的 core_ca7.h 加上 #include "intrinsics.h" /* IAR Intrinsics */ 2. debug 时需要修改每个工程下的 ddr_init.jlinkscript,参考链接 Solved: How to conn…

使用C语言实现杨氏矩阵并找出数字

前言 过了五一假期,咋们经过了一个假期的休息,要继续学习了,不能偷懒哦!! 今天让我们来看看如何在一个杨氏矩阵中找出自己想找到的数字。 首先,我们要了解一下杨氏矩阵到底是什么,如果一个矩阵中…