Spring启动流程和循环依赖

文章目录

    • 概览
    • 对Spring的理解
    • Spring启动流程
    • Spring循环依赖与三级缓存

概览

Spring是一个轻量级的Java开源框架,为了解决企业应用开发的复杂性而创建的。Spring的核心是控制反转(IOC)和面向切面(AOP)。

简单来说,Spring是一个分层的JavaSE/EE 一站式轻量级开源框架。在每一层都提供支持。

  • 表示层:spring mvc
  • 业务层:spring
  • 持久层:jdbctemplate、spring data

请添加图片描述

对Spring的理解

Spring是一个轻量级的框架,简化我们的开发,里面重点包含两个模块分别是IOC和AOP。

  • IOC叫控制反转,在没用IOC之前都要手动new创建对象,使用IOC之后由容器进行对象的创建,并且由容器来管理对象,减去了开发上的成本,提高了工作效率。
  • AOP叫面向切面编程,在实际项目开发中需要嵌入一些与业务不想关的代码的时候就可以使用AOP。比如,权限日志的增加。

Spring虽然把它当成框架来使用,但其本质是一个容器,即IOC容器,里面最核心是如何创建对象和管理对象,里面包含了Bean的生命周期和Spring的一些扩展点,包含对AOP的应用。
除此之外,Spring真正的强大之处在于其生态,它包含了Spring Framework、Spring Boot、Spring Cloud等一些列框架,极大提高了开发效率。

Spring启动流程

参考:https://blog.csdn.net/scjava/article/details/109587619

请添加图片描述

核心方法AbstractApplicationContext#refresh()

public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
          // Allows post-processing of the bean factory in context subclasses.
          postProcessBeanFactory(beanFactory);

          // Invoke factory processors registered as beans in the context.
          invokeBeanFactoryPostProcessors(beanFactory);

          // Register bean processors that intercept bean creation.
          registerBeanPostProcessors(beanFactory);

          // Initialize message source for this context.
          initMessageSource();

          // Initialize event multicaster for this context.
          initApplicationEventMulticaster();

          // Initialize other special beans in specific context subclasses.
          onRefresh();

          // Check for listener beans and register them.
          registerListeners();

          // Instantiate all remaining (non-lazy-init) singletons.
          finishBeanFactoryInitialization(beanFactory);

          // Last step: publish corresponding event.
          finishRefresh();
      }

      catch (BeansException ex) {
         // ... 
      }

      finally {
         // ...
      }
  }
}
  1. prepareRefresh 准备刷新容器,此方法做一些刷新容器的准备工作:
    • 设置开启时间和对应标志位
    • 获取环境对象
    • 设置监听器和一些时间的集合对象
  2. obtainFreshBeanFactory 创建容器对象:DefaultListableBeanFactory;加载xml配置文件属性值到工厂中,最重要的是BeanDefinition
  3. prepareBeanFactory 完成bean工厂的某些初始化操作
    • 设置BeanDefinition的类加载器
    • 设置spring容器默认的类型转换器
    • 设置spring解析el表达式的解析器
    • 添加一个Bean的后置处理器ApplicationContextAwareProcessor
    • 将bean工厂的一些类,比如ApplicationContext直接注册到单例池中
    • 去除一些在byType或者byName的时候需要过滤掉的一些bean(spring在依赖注入的时候会先在这些默认注册的bean中进行byType找,如果找到了,就加入到列表中,简单来说就是比如你在bean中依赖注入了ApplicationContext context,那么spring会把默认注册的这些bean中找到然后进行注册)
    • 将系统的环境信息、spring容器的启动环境信息、操作系统的环境信息直接注册成一个单例的bean
  4. postProcessBeanFactory 这里是一个空壳方法,spring目前还没有对他进行实现;这个方法是留给子类进行实现的,后续可以添加一些用户自定义的或者默认的一些特殊的后置处理器工程到beanFactory中去
  5. invokeBeanFactoryPostProcessors 调用后置处理器;将系统中所有符合条件的普通类都扫描成了一个BeanDefinition 并且放入到了beanDefinitionMap中,包括业务的bean,ban的后置处理器、bean工厂的后置处理器等等
    • 将标记为容器单例类扫描成BeanDefinition放入BeanDefinition Map
    • 处理@Import注解
    • 如果我们的配置类是@Configuration的,那么会生成这个配置类的CGLIB代理类,如果没有加@Configuration,则就是一个普通Bean
  6. registerBeanPostProcessors 从beanDefinitionMap中取出bean的后置处理器然后放入到后置处理器的缓存列表中
  7. initMessageSource 初始化国际化资源信息
  8. initApplicationEventMulticaster 事件注册器初始化
  9. onRefresh 空壳方法,留给子类实现
  10. registerListeners 将容器中和BeanDefinitionMap中的监听器添加到事件监听器中
  11. finishBeanFactoryInitialization 创建单例池,将容器中非懒加载的Bean,单例bean创建对象放入单例池中,包括容器的依赖注入
  12. finishRefresh 容器启动过后,发布事件

Spring循环依赖与三级缓存

请添加图片描述

Spring循环依赖调用流程:

在BeanA中注入BeanB,BeanB中注入BeanA,在BeanA创建的过程中,会先判断容器中A是否存在,如果不存在会先初始化BeanA,然后给BeanA赋值,此时会给BeanA里的BeanB属性赋值,在赋值之前会将创建BeanA的流程放到三级缓存中(三级缓存为Map结构,key为String,value为函数式接口); 由于BeanA里面包含BeanB,所以接下来给BeanB执行创建流程,判断容器中是否存在BeanB,给属性B赋值,此时会给BeanB里的BeanA属性赋值。

在判断容器中是否存在该Bean时,查找顺序为:一级缓存->二级缓存->三级缓存,经历过上面的步骤后,此时三级缓存中A和B都有值(为BeanA、B的创建流程),不需要再进行初始化操作,然后将会执行BeanA的创建流程并将其放入二级缓存中并删除三级缓存中的值,但是此时BeanA中的BeanB还未赋值进行完全的初始化,
BeanA已经创建,此时会将BeanA赋值给BeanB中的A属性,至此BeanB已经完全赋值,然后将完全赋值的BeanB放入一级缓存中并删除三级缓存中的值,由于BeanB已经完全赋值,此时将其赋值给BeanA,将BeanA放入一级缓存并删除二级缓存,至此循环依赖问题解决。

Spring循环依赖大致调用思路:

  • 第一次:A,容器是否存在?(一级缓存->二级缓存->三级缓存)初始化A,-> 将A的创建流程加入三级缓存 -> 给A赋值
  • 第二次:B,容器中是否存在?(一级缓存->二级缓存->三级缓存)初始化B -> 将B的创建流程加入三级缓存 -> 给B赋值
  • 第三次:A的三级缓存中有值,不需要进行初始化操作,执行创建A的流程,将其放入二级缓存,返回值给到创建B,此时B已经创建完全,将其加入一级缓存,然后将该返回值给到A,将A加入一级缓存,至此循环依赖问题解决。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

性能优化 - 你知道CSS有哪些优化方案吗

难度级别:中高级及以上 提问概率:70% CSS是前端开发工作中必不可少的技能之一,同时也是网页开发中必不可少的重要元素之一。但很多人所开发的项目本身对性能要求并不高,再加上项目周期紧张,久而久之,也就容易养成不考虑细节的习惯,觉得C…

从0开始创建单链表

前言 这次我来为大家讲解链表,首先我们来理解一下什么是单链表,我们可以将单链表想象成火车 每一节车厢装着货物和连接下一个车厢的链子,单链表也是如此,它是将一个又一个的数据封装到节点上,节点里不仅包含着数据&…

NzN的数据结构--二叉树part2

上一章我们介绍了二叉树入门的一些内容,本章我们就要正式开始学习二叉树的实现方法,先三连后看是好习惯!!! 目录 一、二叉树的顺序结构及实现 1. 二叉树的顺序结构 2. 堆的概念及结构 3. 堆的实现 3.1 堆的创建 …

90天玩转Python—10—基础知识篇:函数详解

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…

循环单链表算法库

学习贺老师数据结构 数据结构之自建算法库——循环单链表_循环单链表 csdn-CSDN博客​​​​​​ 整理总结出的循环单链表算法库 v1.0 : 基本实现功能 v2.0(2024.4.6): 修复Delete_SpecificLocate_CyclicList()删除节点函数bug,添加验证删除节点是否超范围判断 目录 1.主要功能…

Blender2.83 下载地址及安装教程

Blender是一款开源的3D计算机图形软件,广泛应用于动画制作、游戏开发、建模、渲染等领域。它提供了一套强大的工具和功能,让用户能够进行三维建模、动画制作和视觉效果的创作。 Blender支持多种文件格式的导入和导出,使用户能够与其他软件进…

【Linux源码学习】(一)源码下载、解压说明

目录 一、Linux源码下载地址 二、使用7z解压 一、Linux源码下载地址 官网下载:The Linux Kernel Archives 我们可以到这个地址下载各种版本的压缩包:即上图对应的http网址。 Index of /pub/ 选择Linux 找内核代码 这里直接选择最新的6.x 然后往下翻&…

《猎灵online》游戏完整源码(源码+客户端+服务端+文档+工具),云盘下载

《猎灵》是一款由国内知名开发运营开发的大型3D魔幻网游,《猎灵》研发团队突破诸多瓶颈,首创“全自由无限制PK”,让玩家拒绝无意义等待,自由作战不受任何束缚,真正的实现想战就战,游戏创建了六界神魔乱斗的…

单调栈用法

文章目录 1. 单调栈1.1 理解单调栈(模板)1.2 每日温度1.3 子数组的最小值之和1.4 柱状图中最大的矩形1.5 最大矩形1.6 最大宽度坡1.7 去除重复字母 1. 单调栈 单调栈经典的用法: 对每个位置都求: 当前位置的左侧比当前位置的数…

UDP网络程序

上一章中&#xff0c;我们介绍了socket&#xff0c;以及TCP/UDP协议。这一章带大家实现几个UDP协议的网络服务。我们需要一个 服务端和一个客户端。 1.服务端实现 1.1socket函数 #include <sys/types.h> #include <sys/socket.h>int socket(int domain, in…

【JAVA基础篇教学】第六篇:Java异常处理

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第五篇&#xff1a; Java异常处理。 异常处理是Java编程中重要的一部分&#xff0c;它允许开发人员在程序运行时检测和处理各种错误情况&#xff0c;以保证程序的稳定性和可靠性。在Java中&#xff0c;异常被表示为对象&am…

【 书生·浦语大模型实战营】作业(三):“茴香豆” 搭建你的RAG 智能助理

【 书生浦语大模型实战营】学习笔记&#xff08;三&#xff09;&#xff1a;“茴香豆” 搭建你的RAG 智能助理作业 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI…

JVM参数列表

-client :设置JVM使用client模式,特点启动较快(神机不明显(I5/8G/SSD)) -server :设置JVM使用server模式。64位JDK默认启动该模式 -agentlib:libname[options] :用于加载本地的lib -agentlib:hprof :用于获取JVM的运行情况 -agentpath:pathnamep[options] :加载制定路径的本…

PHP01——php快速入门 之 使用phpstudy快速搭建PHP环境

PHP01——php快速入门 之 使用phpstudy快速搭建PHP环境 0. 前言1. 下载小皮面板1.1 下载phpstudy&#xff08;小皮面板&#xff09;1.2 启动、简单访问1.2.1 启动Apache1.2.2 访问1.2.3 访问自定义文件或页面 2. 创建网站2.1 创建网站2.2 可能遇到的问题2.2.1 hosts权限问题&am…

极海APM32电机驱动板记录(二)

文章目录 1、解除写保护2、极海驱动板资源概述3、新建工程4、点灯5、嘀嗒定时器6、中断7、串口打印8、adc读取9、i2c尝试10、定时器测试11、电机驱动pwm测试 上一篇文章算是简单了解了一下极海的板子开发环境吧&#xff0c;结果前几天板子来了&#xff0c;然后发现一个大bug&am…

力扣题目 19:删除链表的倒数第N个节点 【python】

&#x1f464;作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a; 码上找工作http://t.csdnimg.cn/Q59WX 作者专栏每日更新&#xff1a; LeetCod…

Qt-绘制多边形、椭圆、多条直线

1、说明 所有的绘图操作是在绘图事件中进行。mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWi…

C++ 类和对象(一)

目录 0.前言 1.面向过程&面向对象 1.1面向过程编程&#xff08;PP&#xff09; 1.2面向对象编程&#xff08;OOP&#xff09; 1.3从C到C 2.类的引入 2.1C语言中的结构体 2.2C中类的引入 2.3结构体与类的区别 2.4为什么引入类 3.类的定义 3.1声明与定义不分离 …

【Java探索之旅】从输入输出到猜数字游戏

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java编程秘籍 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、输入输出1.1 输出到控制台1.2 从键盘输入 二、猜数字游戏2.1 所需知识&#xff1a…

【动态规划】【01背包】Leetcode 1049. 最后一块石头的重量 II

【动态规划】【01背包】Leetcode 1049. 最后一块石头的重量 II 解法 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法 &#x1f612;: 我的代码实现> 动规五部曲 ✒️确定dp数组以及下标的含义 dp[j]表示容量为…