一丶前言

前面我们了解到读取xml or 根据扫描路径生成BeanDefinition并注册到BeanFactory,相当于我们具备了生火做饭的原材料:BeanDefinition,接下来就是Spring最为核心的,根据BeanDefinition实例化Bean,并且对Bean的属性进行依赖注入

其中Spring给了我们众多的扩展点,也涉及到面试常问的点——循环依赖的问题,本章我们探讨较为简单的内容——Spring怎么实例化一个Bean,根据JavaSE知识,我们知道实例化一个Bean 可以通过new or 反射的方式,Spring也不外呼这两种方式

二丶源码学习的简单例子

这里我就定义了两个类,模拟工作中最常见的场景

debug 入口

三丶Bean的实例化

完成BeanFactory 所有Bean的实例化和初始化,是DefaultListableBeanFactory的preInstantiateSingletons方法进行处理的,首先会获取所有Bean的名称,循环处理每一个BeanDefinition

可以看到Spring只会先初始化非抽象,且是单例,且非懒加载的Bean,且对FactoryBean存在特殊处理,这里对FactoryBean按下不表,接下来Bean的实例化和初始化是调用getBean(bean名称)进行实例化和初始化的,getBean方法实际就是直接调用doGetBean方法的

1.构造bean的前置操作

1.1获取bean的名称

1.2从单例池中获取bean对象

singletonObjects被称为一级缓存 是一个ConcurrentHashMap key是bean的名称 value是bean的示例
注意上面的方法,如果单例池中有那么也不会进入if 直接返回了
这就是为什么单例只会创建一次,只存在一个实例

1.3标记当前bean已经创建

其实为什么还没有创建就标记为创建了,我不是很理解

2.加载当前bean 依赖的bean

3.处理单例bean

注意这里的addSingletion 我标注了注册到单例池,但是不仅仅是注册到单例池,这和spring的循环依赖密切相关,后续循环依赖分析的时候进行详细学习

我们可以发现这个getSingleton方法,功能是,如果当前bean在单例池没有,那么调用ObjectFactory的getObject方法获取,在外层其实调用了createBean方法,让我们来看看createBean

3.1createBean

这个方法其实是在AbstractAutowireCapableBeanFactory中实现( DefaultListableBeanFactory的父类)AbstractAutowireCapableBeanFactory的定位是一个提供 bean 创建(使用构造函数解析)、属性填充、和初始化的BeanFactory

3.1.1实例化bean的前置操作

我们重点看下这个resolveBeforeInstantiation 方法这是spring给我们的一个扩展点

  • InstantiationAwareBeanPostProcessor 具备实例化感知能力的bean后置处理器

这里关注下postProcessBeforeInstantiation 和 postProcessAfterInitialization 方法

注意Instantiation 和 Initialization 的区别,前者是实例化(反射生成bean对象,任何属性都没有赋值,生成对象叫实例化)后者是初始化(属性赋值,初始化方法调用叫初始化)

  • applyBeanPostProcessorsBeforeInstantiation 提供我们自己定一个bean,而不是spring帮我们反射生成bean的扩展,后续spring不会帮我们进行依赖注入

  • applyBeanPostProcessorsAfterInitialization 提供对bean进行代理的扩展

3.2doCreateBean

如果前面的InstantiationAwareBeanPostProcessor 没有返回一个bean 那么接下来就是spring容器为我们生成这个bean

这里的策略是CglibSubclassingInstantiationStrategy,提供普通的构造方法反射方式和CGLIB两种方式

  1. 构造方法反射生成

  2. CGLIB

    具体怎么实现lookup和methodRepalcer的,后续学习一下cglib

4.回调MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition

所有的MergedBeanDefinitionPostProcessor 调用其postProcessMergedBeanDefinition 方法,

回调 postProcessMergedBeanDefinition 方法时,已经拿到了 merged bean definition,并且还未开始 poplateBean 填充 bean 属性、
initlializeBean 初始化 bean 对象,
因此可以在这里对 merged bean definition 进行一些操作
,在 poplateBean 或 initlializeBean 阶段使用前面操作结果实现所需功能 @PostConstruct,@PreInit @Resouce,@Autowired
@InitMethod 都在这里实现的
具体如何实现的,后续的源码学习笔记再进行总结

5.提前暴露对象

spring解决循环依赖的重点步骤
如何解决循环依赖的,后续的源码学习笔记再进行总结

addSingletonFactory 会向singletonFactories put一条记录

singletonFactories key是bean名称 value 是ObjectFactory

Spring源码学习笔记6——Spring bean的实例化的更多相关文章

  1. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

  2. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  3. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  4. Spring源码学习笔记9——构造器注入及其循环依赖

    Spring源码学习笔记9--构造器注入及其循环依赖 一丶前言 前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在 ...

  5. spring源码学习笔记之容器的基本实现(一)

    前言 最近学习了<<Spring源码深度解析>>受益匪浅,本博客是对学习内容的一个总结.分享,方便日后自己复习或与一同学习的小伙伴一起探讨之用. 建议与源码配合使用,效果更嘉, ...

  6. Spring源码学习笔记之bean标签属性介绍及作用

    传统的Spring项目, xml 配置bean在代码中是经常遇到, 那么在配置bean的时候,这些属性的作用是什么呢? 虽然说现在boot项目兴起,基于xml配置的少了很多, 但是如果能够了解这些标签 ...

  7. Spring源码学习笔记之基于ClassPathXmlApplicationContext进行bean标签解析

    bean 标签在spring的配置文件中, 是非常重要的一个标签, 即便现在boot项目比较流行, 但是还是有必要理解bean标签的解析流程,有助于我们进行 基于注解配置, 也知道各个标签的作用,以及 ...

  8. Spring源码学习-容器BeanFactory(五) Bean的创建-探寻Bean的新生之路

    写在前面 上面四篇文章讲了Spring是如何将配置文件一步一步转化为BeanDefinition的整个流程,下面就到了正式创建Bean对象实例的环节了,我们一起继续学习吧. 2.初始化Bean对象实例 ...

  9. spring源码阅读笔记06:bean加载之准备创建bean

    上文中我们学习了bean加载的整个过程,我们知道从spring容器中获取单例bean时会先从缓存尝试获取,如果缓存中不存在已经加载的单例bean就需要从头开始bean的创建,而bean的创建过程是非常 ...

  10. Spring 源码学习(4)—— bean的加载part 1

    前面随笔中,结束了对配置文件的解析工作,以及将配置文件转换成对应的BeanDefinition存储在容器中.接下来就该进行bean的加载了. public Object getBean(String ...

随机推荐

  1. fatal: 无法访问 'https://github.com/nmww/lingyun.git/':Failed to connect to github.com port 443 after 13 ms: Connection refused

    fatal: 无法访问 'https://github.com/nmww/lingyun.git/':Failed to connect to github.com port 443 after 13 ...

  2. .Net核心级的性能优化(GC篇)

    1.前言 大部分人对于.Net性能优化,都停留在业务层面.或者简单的.Net框架配置层面.本篇来看下.Net核心部分GC垃圾回收配置:保留VM,大对象,独立GC,节省内存等.Net8里面有很多的各种G ...

  3. Util应用框架Web Api开发环境搭建

    要使用Util应用框架开发项目,首先需要搭建合适的开发环境. 迈出第一步,对于很多.Net新人可能并不简单. 如果你对.Net环境并不熟悉,请尽量按照本文档进行操作. 操作系统 请安装 Windows ...

  4. 栈溢出-GOT表劫持测试

    1.目标程序源代码 char name[64]; int main(){ int unsigned long long addr; setvbuf(stdin,0,2,0); setvbuf(stdo ...

  5. 数组操作 filter和find

    现在有个需求: 后端给一个list过来,1-4,有就显示,没有前面四个card就空着,从第五个开始,有数据就循环出来,区别他们的kind字段. 这里想了很久怎么写,最后决定,洗数据. 就是从给给的数据 ...

  6. 从windows到linux,图形化操作到命令行操作讲解

    作为一个后端开发人员,刚开始进入到职场中,linux还不是必备项.但是随着开发经验的提升,慢慢就会接触到linux,所以就有了那句:开发必须要会linux.一开始我也不知道linux是干嘛的,学那些命 ...

  7. NLP机器翻译全景:从基本原理到技术实战全解析

    机器翻译是使计算机能够将一种语言转化为另一种语言的技术领域.本文从简介.基于规则.统计和神经网络的方法入手,深入解析了各种机器翻译策略.同时,详细探讨了评估机器翻译性能的多种标准和工具,包括BLEU. ...

  8. 零基础快速上手STM32开发(手把手保姆级教程)

    零基础快速上手STM32开发(手把手保姆级教程) 1. 前言 作为一名嵌入式工程师,STM32 是必须要学习的一款单片机,同时这款单片机资料足够多,而且比较简单,非常适合初学者入门. STM32 是一 ...

  9. offscreenCanvas+worker+IndexedDB实现无感大量图片缓存

    一个有必要实现的需求 因为项目中需要使用canvasTexture(一个threejs3d引擎中的材质类型),绘制大量的图片,每次使用都会请求大量的oss图片资源,虽然重复请求会有磁盘缓存但毕竟这个磁 ...

  10. 大白话说Python+Flask入门(三)

    写在前面 今天状态很不好,我发现学这部分知识的时候,会出现溜号或者注意力无法集中的情况. 我能想到的是,大概率是这部分知识,应该是超出了我现在的水平了,也就是说我存在知识断层了,整体感觉真的是一知半解 ...