Spring IOC 源码解读

news2024/11/25 7:28:11

将回答以下问题:

  1. BeanFactory 和 ApplicationContext 之间的关系和区别。
  2. 一个 Bean 是如何被注入到 IOC 容器里,中间经历了什么过程(Bean 的生命周期)。

先入为主

假设你已经有如下经验:

  • 什么是 IOC。
don‘t call us, we‘ll call you - 好莱坞原则
  • 依赖查找和依赖注入。
依赖查找是 IOC 容器中的对象通过容器提供的 API 主动获取依赖对象
依赖注入是 IOC 容器将依赖对象直接注入到被依赖对象中
都是 IOC 容器实现的方式
  • Spring framework 的使用经验。

源码版本

5.3.8

涉及到的 Spring 模块

  • spring-context
  • spring-bean
  • spring-core

ApplicationContext 和 BeanFactory

 https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-introduction

The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework’s IoC container. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext is a sub-interface of BeanFactory. It adds:

  • Easier integration with Spring’s AOP features
  • Message resource handling (for use in internationalization)
  • Event publication
  • Application-layer specific contexts such as the WebApplicationContext for use in web applications.

In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container. For more information on using the BeanFactory instead of the ApplicationContext, see The BeanFactory.

  • 两者都是 IOC容器。
  • ApplicationContext 继承自 BeanFactory,同时内部还组合了一个 BeanFactory 的实现(DefaultListableBeanFactory)。
org.springframework.context.support.AbstractApplicationContext#getBeanFactory

  • BeanFactory 提供了最基础的 IOC 容器功能,例如:依赖查找。
  • ApplicationContext 是 BeanFactory 的超集,除了拥有 BeanFactory 的能力之外,还提供:
    • AOP
    • 资源管理
    • 国际化
    • 事件
    • Environment 抽象
  • BeanFactory 只会在查找 Bean 时才去创建(实例化,初始化)Bean,ApplicationContext 在启动时就已经创建好所有的 Bean。
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization

Bean 生命周期

1. 启动 spring 应用上下文

org.springframework.context.support.ClassPathXmlApplicationContext

AbstractApplicationContext#refresh

  • 创建并初始化一个内部的 BeanFactory(DefaultListableBeanFactory)
  • AbstractRefreshableApplicationContext#refreshBeanFactory

2. 加载Bean元信息

Bean 定义中的 id,name,scope,primary 等统称为 Bean 元信息
org.springframework.beans.factory.config.BeanDefinition

AbStractXmlApplicationContext#loadBeanDefinitions

AbstractBeanDefinitionReader#loadBeanDefinitions

XmlBeanDefinitionReader#loadBeanDefinitions

2.1 解析 BeanDefinition

DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

DefaultBeanDefinitionDocumentReader#processBeanDefinition

解析 xml 构建 BeanDefinitionHolder

BeanDefinitionHolder 包含 beanName,aliaes,BeanDefinition

默认 beanName = id。如果没有指定 id,容器会为 Bean 创建一个唯一的 beanName

问题:容器创建的唯一的 beanName 的规则是怎样的。

org.springframework.beans.factory.support.DefaultBeanNameGenerator#generateBeanName

2.2 注册 BeanDefinition 到 BeanFactory

DefaultListableBeanFactory#registerBeanDefinition

beanDefinitionMap(ConcurrentHashMap) 维护 BeanName 和 BeanDefinition 的对应关系

beanDefinitionNames(ArrayList) 保证 Bean 注册的顺序

2.3 合并 BeanDefinition

AbstractBeanFactory#getMergedLocalBeanDefinition

继承配置

最终所有的 BeanDefinition 都会被构建成 RootBeanDefinition

3. Bean 实例化

AbstractApplicationContext#finishBeanFactoryInitialization

DefaultListableBeanFactory#preInstantiateSingletons

AbstractBeanFactory#getBean

DefaultSingletonBeanRegistry#getSingleton

AbstractAutowireCapableBeanFactory#createBean

3.1 Bean Class 加载

AbstractBeanFactory#resolveBeanClass

AbstactBeanDefinition#resolveBeanClass

BeanDefinition 中的 beanClass(Object) 是以 String 定义,通过 spring 的 ClassUtil.forName 处理成 Class 类型,并通过 ClassLoader 加载

3.2 实例化前阶段

AbstractAutowireCapableBeanFactory#createBean

AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation

如果实现并注册了 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 会触发回调

3.3 实例化阶段

AbstractAutowireCapableBeanFactory#doCreateBean

AbstractAutowireCapableBeanFactory#createBeanInstance

  • 如果 BeanDefinition 中指定了工厂方法(factory-method) 则通过工厂方法AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod
  • 如果 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors 指定了构造器,或 BeanDefinition 中的 autowire-mode 为 constructor,或 BeanDefinition 中指定了构造参数(constructor-arg),或 BeanFactory#getBean 方法传了构造参数。则通过 AbstractAutowireCapableBeanFactory#autowireConstructor
  • 默认使用无参构造器,创建的实例会被包装成 BeanWrapper,BeanWrapper 中的 wrappedObject 就是最终会被注入到 IOC 容器中的 Bean。

问题:autowire-mode = constructor 时,构造器中的构造参数的注入是 byType ,还是byName。

DefaultListableBeanFactory#doResolveDependency

DefaultListableBeanFactory#determineAutowireCandidate

注意是否有 primary = ture 的 Bean

3.4 实例化后阶段

AbstractAutowireCapableBeanFactory#populateBean

如果实现并注册了 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation 会触发回调

此时 Bean 已经完成实例化,但是并未填充属性

4. Bean 属性填充

BeanDefinition 中包含 Bean 的属性列表(org.springframework.beans.PropertyValues)
Bean 的属性会被构建成 org.springframework.beans.PropertyValue

AbstractAutowireCapableBeanFactory#populateBean

4.1 填充前阶段

如果实现并注册了 InstantiationAwareBeanPostProcessor#postProcessProperties 会触发回调

此阶段可以对 PropertyValue 做修改

4.2 构建属性描述

java.beans.PropertyDescriptor

包含属性的读方法引用(readMethodRef,通常是getter),写方法引用(writeMethodRef,通常是setter)等信息

AbstractAutowireCapableBeanFactory#filterPropertyDescriptorsForDependencyCheck

BeanWrapper#getPropertyDescriptors

java.beans.Introspector#getTargetPropertyInfo

过滤出所有有读方法和写方法的属性。

构建完成的 PropertyDescriptor 会作为 BeanWrapper 的属性。

4.3 填充属性值

AbstractAutowireCapableBeanFactory#applyPropertyValues

4.3.1 属性值类型转换

  • BeanDefinitionValueResolver#resolveValueIfNecessary,获取 BeanDefinition 中定义的属性值。
  • AbstractAutowireCapableBeanFactory#convertForPropertyBeanWrapperImpl#convertForProperty
  • 根据 PropertyDescriptor 中的读方法引用和写方法引用,通过反射获取转换目标类型,目标类型会被构建成 org.springframework.core.convert.TypeDescriptor。
  • 经过转换后的属性值,会记录在 PropertyDescriptor 的 convertedValue 属性中。

问题:获取到的转换目标类型是 getter 的返回类型,还是 setter 的参数类型。

org.springframework.core.convert.Property#resolveMethodParameter

4.3.2 调用 Bean 属性的 writeMethod 赋值

org.springframework.beans.BeanWrapperImpl.BeanPropertyHandler#setValue

5. Bean 初始化

AbstractAutowireCapableBeanFactory#initializeBean

5.1 初始化前阶段

Aware 接口回调

org.springframework.beans.factory.BeanNameAware

org.springframework.beans.factory.BeanClassLoaderAware

org.springframework.beans.factory.BeanFactoryAware

org.springframework.context.EnvironmentAware

org.springframework.context.EmbeddedValueResolverAware

org.springframework.context.ResourceLoaderAware

org.springframework.context.ApplicationEventPublisherAware

org.springframework.context.MessageSourceAware

org.springframework.context.ApplicationContextAware

org.springframework.context.ApplicationStartupAware

AbstractAutowireCapableBeanFactory#invokeAwareMethods

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

如果实现并注册了 BeanPostProcessor#postProcessBeforeInitialization 会触发回调

5.2 初始化阶段

AbstractAutowireCapableBeanFactory#invokeInitMethods

  • 如果实现了 org.springframework.beans.factory.InitializingBean 接口,会回调 InitializingBean#afterPropertiesSet
  • 如果 BeanDefinition 中有自定义初始化方法(init-method),会回调自定义初始化方法

AbstractAutowireCapableBeanFactory#invokeCustomInitMethod

5.3 初始化后阶段

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization

如果实现并注册了 BeanPostProcessor#postProcessAfterInitialization 会触发回调

6. 注册 Bean(singleton) 到 IOC 容器中

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#registeredSingletons

DefaultSingletonBeanRegistry#addSingleton

问题:spring 是如何解决循环依赖问题。

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

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

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

相关文章

verilog手撕代码2——各种加法器介绍——真值表、表达式、电路图

文章目录 前言一、半加器二、全加器三、串行/行波进位加法器(Ripple-Carry Adder/RCA)四、超前进位加法器(Lookahead Carry Adder/LCA)五、进位保存加法器(Carry Save Adder/CSA) 前言 2023.4.25 一、半加…

Terraform

文章目录 简介安装简单使用案例 概念原理状态管理Backend 远程状态存储机制 配置语法Argument 参数Block 块terraform块required_providersbackend provider块: 与基础设施交互resource块: 定义基础架构data块: 数据源 表达式(Experssion)和函数(Functions)变量variable 输入变…

【Celery】任务Failure或一直超时Pending

编写背景 task进入队列后,部分任务出现Failure或者一直Pending,且业务代码没有报错。 运行环境 celery配置 from celery import Celery broker redis://:127.0.0.1:6379/1 backend redis://:127.0.0.1:6379/2 app Celery(brokerbroker,backendbackend,includ…

【文心一言】广告文案、演讲稿与请假条自动生成

前言 作为一名大学生而言,平时参加或者举办一些学校组织的活动的时候,总是避免不了需要准备一些演讲稿、广告宣传文案等内容,甚至于在疫情十分严重的这几年内,如何跟老师“委婉的”请假,也成为了我日常头疼的事情。但在…

React之redux的模板

文章目录 以下为模板代码安装(添加 Redux Toolkit 和 React-Redux 依赖包到你的项目中)以下为项目目录在store/index.js里面的模板创建模块(模块化思想),这里就是模板,所有模块通用(src/features/userSlice.js)在main.jsx引入模板(只需要看下面画横线的四行)在组件内使用 以下是…

【网课平台】Day16.项目优化:压测、加缓存优化与分布式锁

文章目录 一、压力测试1、优化需求2、性能指标3、安装Jmeter4、压力测试5、优化日志 二、缓存优化1、给接口加Redis缓存2、缓存穿透3、解决缓存穿透4、缓存雪崩5、缓存击穿 三、分布式锁1、本地锁的问题2、IDEA一个项目启动多个实例3、分布式锁4、Redis NX实现分布式锁5、Redis…

多项式加法(用 C 语言实现)

目录 一、多项式的初始化 二、多项式的创建 三、多项式的加法 四、多项式的输出 五、清除链表 六、主函数 用链表实现多项式时,每个链表节点存储多项式中的一个非零项,包括系数(coef)和指数(exp)两个…

Java8新特性函数式编程 - Lambda、Stream流、Optional

1.Lambda表达式 1.1 概述 ​ Lambda是JDK8中一个语法糖。他可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什么对象。而是更关注我们对数据进行了什么操作。 1.2 核心原则 可推导可省略 1.3 基本格式 (参数列表)->{代码}例一…

python毕业设计之django+vue公司企业物流信息管理系统

基于 开发语言:Python 框架:django Python版本:python3.7.7 数据库:mysql 数据库工具:Navicat 开发软件:PyCharm 语言设计并实现了速运公司物流信息管理系统。该系统基于B/S即所谓浏览器/服务器模式&…

智慧物流信息系统开发需具备哪些功能?

智慧物流软件开发公司在制作管理系统的时候,需要具备的功能有哪些呢? 一、采集跟踪功能。 (1)、信息采集:信息采集跟踪系统是智能物流系统的重要组成部分。物流信息采集系统主要由RFID射频识别系统和Savan…

【Hadoop-HDFS】HDFS中Fsimage与Edits详解

【Hadoop-HDFS】HDFS中Fsimage与Edits详解 1)概述2)NameNode元数据解析3)Fsimage3.1.Fsimage 的作用3.2.FSimage 的文件信息查看 4)Edits4.1.Edits 的作用4.2.Edits 的文件信息查看 5)元数据信息目录的配置 1&#xff…

【2023.04.28】Windows配置MongoDB服务

【2023.04.28】Windows配置MongoDB服务 1、背景2、操作2.1 配置环境变量2.2 配置本地Windows MongoDB服务 环境:Windows11,Mongo 6.0.5【该版本没有mongo.exe】 1、背景 某一天想使用电脑以前安装的 MongoDB,发现用 Navicat 连接不了&#…

4个很多人都不知道的现代JavaScript技巧

JavaScript在不断的进化和升级,越来越多的新特性让我们的代码变得更加简洁。因此,今天这篇文章,我将跟大家分享 4 个不常用的 JavaScript 运算符。让我们一起研究它们。 1.可选的链接运算符 这个功能非常好用,它可以防止我的代码…

pwm调节亮度

文章目录 运行环境:1.1 pwm1)占空比2)A板原理图3)PE11引脚配置4)定时器Timers配置 2.1代码解释1)定时器1初始化函数2)启动定时器中断3)启动PWM/设置占空比4)launch设置5) 编译调试 3.1实验效果 运行环境: ubuntu18.04.melodic 宏基暗影骑士笔记本 stm32…

Leetcode202. 快乐数

Every day a leetcode 题目来源:202. 快乐数 解法1:hash 根据几个例子,我们发现只有2种结果: 最终会得到1最终进入一个循环 其实得到1后,继续计算(将该数替换为它每个位置上的数字的平方和&#xff09…

美妆“数字员工”来了!丸美:每月节省30人日!提升员工幸福感,企业效益稳增

美妆,因其效果可视觉化呈现的特征,决定了美妆品牌与直播带货的高匹配度。流量,是直播商家深入了解粉丝参与情况和商品销售状况的重要依据。因此,美妆商家需要每天下载直播数据报表,监测流量、成交变化趋势,…

数据可视化 —— 小练习1 KMeans聚类并数据可视化图像像素点

数据可视化Task1 任务描述:对图片RGB点进行Kmeans聚类,并将结果数据可视化于前端浏览器上 实验平台: Visual Studio CodeHTML/CSS/JavascriptEdge/Chorme/Firefox 浏览器Echart.min.js 3.8.5版 (过高的版本浏览器无法include&a…

Python采集豆Top250电影数据 , 看看质量及评分

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 本次案例涉及点: 1、动态数据抓包演示 2、csv文件保存 3、requests模块的使用 4、parsel解析数据的使用 环境介绍: 软件安装 python 3.8 pycharm 不会安装的可以文末名片我获取哦 😎 模块使用…

windows安装flutter

在flutter官网下载flutter 在 Windows 操作系统上安装和配置 Flutter 开发环境 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 下载文件后,解压文件把文件存放在指定位置 打开flutter_console.bat文件 输入flutter doctor flutter报错提示(…

unity-VRTK学习日记1(VRTK4|无头盔开发模拟器SpatialSimulator)

目录 前言 前期准备 1.配置VRTK4: 2.把几个插件给安装好 查看自己安装了哪些VRTK插件 3.添加模拟器 操作方法 操作方法:人话 前言 VRTK的较早版本不适用于Unity的新版本,原因好像是Unity将VR开发功能并入到自家的XR下了。就是之前更新…