Spring源码分析(十三)缓存中获取单例bean
摘要:本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。
介绍过FactoryBean的用法后,我们就可以了解bean加载的过程了。前面已经提到过,单 例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再尝试从singletonFactories中加载。 因为在创建单例bean的时候会存在依赖注人的情况,而在创建依赖的时候为了避免循环依赖, Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加人到 缓存中,一旦下一个bean创建时需要依赖上个bean,则直接使用ObjectFactory。
@Override
@Nullable
public Object getSingleton(String beanName) {
// 参数true设置标识允许早期依赖
return getSingleton(beanName, true);
} /**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 检査缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 如果为空,则锁定全局变量并进行处理
synchronized (this.singletonObjects) {
// 如果此bean正在加载则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策路存储在 singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用预先设定的getObject方法
singletonObject = singletonFactory.getObject();
// 记录在缓存中,earlySingletonObjects和singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这个方法因为涉及循环依赖的检测,以及涉及很多变量的记录存取,所以让很多读者摸不着头脑。这个方法首先尝试从singletonObjects面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject 来创建bean,并放到 earlySingletonObjects里面去,并且从singletonFacotories里面remove掉这个ObjectFactory,而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在allowEarlyReference为true的情况下才会使用。
这甩涉及用于存储bean的不同的map,可能让读者感到崩溃,简单解释如下。
| singletonObjects | 用于保存 beanName 和创建 bean 实例之间的关系,bean name -> bean instance |
| singletonFactories | 用于保存beanName 和创建bean的工厂之间的关系,bean name -> ObjectFactory |
| earlySingletonObjects | 也是保存beanName 和创建bean实例之间的关系,与 singletonObjects的不同之处在于,当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检測循环引用 |
| registeredSingletons | 用来保存当前所有已注册的bean |
Spring源码分析(十三)缓存中获取单例bean的更多相关文章
- 5.2:缓存中获取单例bean
5.2 缓存中获取单例bean 介绍过FactoryBean的用法后,我们就可以了解bean加载的过程了.前面已经提到过,单例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例 ...
- Spring源码分析(十六)准备创建bean
本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多Spring ...
- Spring源码分析(五)获取Document
摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 这一篇开始进行Document加载了,XmlBeanFactoryRea ...
- spring源码分析系列5:ApplicationContext的初始化与Bean生命周期
回顾Bean与BeanDefinition的关系. BeanFactory容器. ApplicationContext上下文. 首先总结下: 开发人员定义Bean信息:分为XML形式定义:注解式定义 ...
- Spring IOC 容器源码分析 - 获取单例 bean
1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...
- 【spring源码分析】IOC容器初始化(六)
前言:经过前几篇文章的讲解,我们已经得到了BeanDefinition,接下来将分析Bean的加载. 获取Bean的入口:AbstractApplicationContext#getBean publ ...
- 【Spring源码分析系列】bean的加载
前言 以 BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beans.xml"));为例查看bean的加载过 ...
- Spring源码分析(十五)获取单例
本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 之前我们讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例be ...
- Spring源码分析——BeanFactory体系之抽象类、类分析(一)
上一篇介绍了BeanFactory体系的所有接口——Spring源码分析——BeanFactory体系之接口详细分析,本篇就接着介绍BeanFactory体系的抽象类和接口. 一.BeanFactor ...
随机推荐
- Code Signal_练习题_Array Replace
Given an array of integers, replace all the occurrences of elemToReplace with substitutionElem. Exam ...
- vue项目中引入bootstrap
(1)引入Jquery文件,需要在bootstrap.min.js 之前引入. 1.npm install jquery --save-dev 2. plugins: [ new webpack.Pr ...
- RNN & LSTM & GRU 的原理与区别
RNN 循环神经网络,是非线性动态系统,将序列映射到序列,主要参数有五个:[Whv,Whh,Woh,bh,bo,h0][Whv,Whh,Woh,bh,bo,h0],典型的结构图如下: 和普通神经网 ...
- MVP+Dagger2+Rxjava+Retrofit+GreenDao 小应用,包含新闻、图片、视频3个大模块,代码整洁干练
练习MVP架构开发的App,算是对自己学过的知识做一个总结,做了有一段时间,界面还算挺多的,代码量还是有的,里面做了大量封装,整体代码整理得很干净,这个我已经尽力整理了.不管是文件(Java.xml. ...
- Android控件显示和隐藏
Android控件都有visibility属性,该属性有三个可能值:visible.invisible.gone.可以通过预设或是Java程序控制这些控件的显示或隐藏. 一.在XML配置文件设置 可见 ...
- centos安装redis,并设置开机自动启动项
安装Redis 1.下载.解压.编译.安装 下载.解压 https://redis.io/download 官网下载redis的*.tar.gz安装包.版本可根据自己需要下载. tar -zxvf r ...
- pjax 和 ajax 的区别
pjax 是一个 jQuery 插件,它通过 ajax 和 pushState 技术提供了极速的(无刷新 ajax 加载)浏览体验,并且保持了真实的地址.网页标题,浏览器的后退(前进)按钮也可以正常使 ...
- c# 编译期常量const和运行时常量readonly
注意:const编译期常量是编译的时候就确定的,可以查看IL代码,是写死的.如果另一个程序集引用后,该程序集没有进行编译,则值不会改变. 看效果: 项目中有2个程序集: 其中:常量在这个程序集中定义并 ...
- springCloud微服务入门
目录 前言 Eureka 注册中心server 新建 配置 服务提供者service 新建 配置 服务消费者controller 新建 配置 使用 Feign负载均衡 前言 springCloud是一 ...
- Replication--复制Token
--创建tokenDECLARE @tokenID AS INT;EXEC sys.sp_posttracertoken @publication = @publication,@tracer_tok ...