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

原文地址:https://www.cnblogs.com/wuxiaofeng/p/9381824.html

时间: 2024-07-28 20:15:23

Spring源码分析(十三)缓存中获取单例bean的相关文章

缓存中获取单例bean

前言 上一篇文章FactoryBean的使用实际上是为了Bean的加载的详细解析进行的介绍FactoryBean,从这篇文章开始,LZ会对Bean的加载过程进行详细的讲述,之前文章Bean的加载只是对Bean的加载过程进行了快速的大致上的过了一遍,详细的解析过程开始... 缓存中获取单例bean 前面的文章Bean的加载已经提到过,单例在Spring的同一个容器中只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再尝试从singletonF

【Spring源码分析】非懒加载的Bean实例化过程(下篇)

doCreateBean方法 上文[Spring源码分析]非懒加载的Bean实例化过程(上篇),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下AbstractAutowireCapableBeanFactory的doCreateBean方法代码: 1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[]

Spring源码分析(五)获取Document

摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 这一篇开始进行Document加载了,XmlBeanFactoryReader类对于文档读取并没有亲历亲为,而是委托给了DocumentLaoder去执行,DocumentLoader是个接口,真正调用的是DefaultDocumentLoader,解析代码如下: /** * Load the {@link Document} at the supplied {@link Inp

spring源码分析系列5:ApplicationContext的初始化与Bean生命周期

回顾Bean与BeanDefinition的关系. BeanFactory容器. ApplicationContext上下文. 首先总结下: 开发人员定义Bean信息:分为XML形式定义:注解式定义 ApplicationContext搜集Bean的定义:存储到BeabFactory容器的中. BeanFactory根据这些BeanDefinition创建Bean.缓存起来供我们使用. [开发人员]--标注-->[Bean定义] ---搜集 -->[BeanDefinition]---创建--

【spring源码分析】IOC容器初始化(六)

前言:经过前几篇文章的讲解,我们已经得到了BeanDefinition,接下来将分析Bean的加载. 获取Bean的入口:AbstractApplicationContext#getBean 1 public Object getBean(String name) throws BeansException { 2 // 检测bean工厂是否存活 3 assertBeanFactoryActive(); 4 return getBeanFactory().getBean(name); 5 } 分

【Spring源码分析系列】bean的加载

前言 以 BeanFactory bf  = new XmlBeanFactory(new ClassPathResource("beans.xml"));为例查看bean的加载过程. 一.首先来看Spring中是如何实现的 1 @Override 2 public Object getBean(String name) throws BeansException { 3 return getBean(name, Object.class); 4 } 5 6 @Override 7 p

Spring源码分析——BeanFactory体系之抽象类、类分析(一)

上一篇介绍了BeanFactory体系的所有接口——Spring源码分析——BeanFactory体系之接口详细分析,本篇就接着介绍BeanFactory体系的抽象类和接口. 一.BeanFactory的基本类体系结构(类为主): 上图可与 Spring源码分析——BeanFactory体系之接口详细分析 的图结合分析,一个以接口为主,一个以类为主(PS:Spring的体系结构要分析清楚,不得不曲线救国啊!不然27寸屏幕给我画估计都装不下.). 具体: 1.7层的类体系继承. 2.Abstrac

【Spring源码分析】原型Bean实例化过程、byName与byType及FactoryBean获取Bean源码实现

原型Bean加载过程 之前的文章,分析了非懒加载的单例Bean整个加载过程,除了非懒加载的单例Bean之外,Spring中还有一种Bean就是原型(Prototype)的Bean,看一下定义方式: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi=&qu

Spring源码分析——BeanFactory体系之抽象类、类分析(二)

上一篇分析了BeanFactory体系的2个类,SimpleAliasRegistry和DefaultSingletonBeanRegistry——Spring源码分析——BeanFactory体系之抽象类.类分析(一),今天继续分析. 一.工厂Bean注册支持——FactoryBeanRegistrySupport 废话不多说,直接看我注释的源码: /* * Copyright 2002-2012 the original author or authors. * * Licensed und