Spring注解驱动开发第47讲——Spring IOC容器创建源码解析(七)之初始化所有剩下的单实例bean(下)
发布日期:2021-06-30 17:56:32 浏览次数:3 分类:技术文章

本文共 13502 字,大约阅读时间需要 45 分钟。

目录一览

写在前面

紧接上讲,我们来继续讲解创建单实例bean的流程。在上一讲末尾,我们看到了这一点,在创建单实例bean之前,InstantiationAwareBeanPostProcessor这种类型的后置处理器中两个方法的执行时机,即先执行其postProcessBeforeInstantiation方法,并看该方法有没有返回值(即创建的代理对象),若有则再执行其postProcessAfterInitialization方法

而且,此时程序停留在了下面这行代码处。

在这里插入图片描述

于是,我们继续按下F6快捷键让程序往下运行,直至运行到下面这行代码处为止。

在这里插入图片描述

这时,resolveBeforeInstantiation方法总算是执行完了。你还记得该方法是干嘛的吗?它是在创建我们单实例bean之前,先来给BeanPostProcessor一个返回其代理对象的机会。但是,此刻是没有返回我们单实例bean的代理对象的,不信你看。

在这里插入图片描述

如果InstantiationAwareBeanPostProcessor这种类型的后置处理器并没有返回我们bean的代理对象,那么接下来该怎么办呢?

那我们只好继续按下F6快捷键让程序往下运行了,继续执行下面的流程,当程序运行到下面这行代码处时,发现调用了一个叫doCreateBean的方法,顾名思义,该方法就是来创建我们bean的实例的。

在这里插入图片描述

那么这个创建bean的流程又是怎样的呢?下面我就来为大家揭晓答案。

单实例bean的创建流程

按下F5快捷键进入doCreateBean方法里面去看一下,如下图所示,可以看到会用BeanWrapper接口来接收我们创建的bean。

在这里插入图片描述

继续按下F6快捷键让程序往下运行,直至运行到下面这行代码处为止,可以看到这儿调用的是一个叫createBeanInstance的方法,顾名思义,它是来创建bean实例的。

在这里插入图片描述

也就是说,创建bean的流程的第一步就是先来创建bean实例。

创建bean实例

当执行完createBeanInstance方法之后,我们bean的对象就创建出来了。那么,我们bean实例的创建流程又是怎样的呢?我们不妨按下F5快捷键进入createBeanInstance方法里面去看一下,如下图所示,可以看到一开始就要来解析一下我们要创建的bean的类型。

在这里插入图片描述

于是,我们继续按下F6快捷键让程序往下运行,由于解析出来的类型为null,所以程序并不会进入到下面的if判断语句中,而是来到了下面这行代码处。

在这里插入图片描述

这块是来干嘛呢?我们可以来详细说一下。首先,在if判断语句中的条件表达式中,你可以看到调用了bean定义信息对象的一个getFactoryMethodName方法,该方法是来获取工厂方法的名字的。我们不妨Inspect一下mbd.getFactoryMethodName()表达式的值,发现其值就是blue,如下图所示。

在这里插入图片描述

为什么叫工厂方法呢?还记得咱们自己编写的Blue对象是如何注册到IOC容器中的吗?如下图所示,我们是使用标注了@Bean注解的blue方法来创建Blue对象并将其注册到IOC容器中的。

在这里插入图片描述

也就是说,以上blue方法就相当于Blue对象的工厂方法。

还是回到Spring的源码中来,现在程序是停留在了if判断语句块内,不难猜测此时就是来执行Blue对象的工厂方法(即blue方法)来创建Blue对象的。我们不妨按下F5快捷键进入instantiateUsingFactoryMethod方法里面去看一下,如下图所示,这块好像是来拿什么构造器解析的,咱也不太懂,哈哈哈😡

在这里插入图片描述

我们就直接按下F6快捷键继续让程序往下运行,运行一步,发现程序来到了ExtConfig配置类的blue方法中,如下图所示。

在这里插入图片描述

继续让程序往下运行,这时可以从Eclipse控制台中看到打印了如下内容,即调用了Blue类的无参构造器创建出了Blue对象。

在这里插入图片描述

是不是可以这样说呢?这儿就是利用工厂方法或对象的构造器创建出bean实例呢?当我们这个bean实例(也即Blue对象)创建出来以后,继续按下F6快捷键让程序往下运行,直至运行到下面这行代码处为止。

在这里插入图片描述

让程序继续往下运行,这时你得不停地按F6快捷键,这一过程中好像是利用反射来创建对象,咱也不用看,直接放过(再说了,你也看不过来😥),直至运行到下面这行代码处为止。

在这里插入图片描述

程序运行至此,咱们这个bean实例(即Blue对象)就创建出来了,只不过该Blue对象刚刚创建出来,空空如也,什么都没有。

接着,让程序继续往下运行,直至再次运行回doCreateBean方法中,如下图所示。

在这里插入图片描述

这时,以上createBeanInstance方法就算是执行完了,也就是说,创建出了我们的bean实例(即Blue对象)。

最后,让程序继续往下运行,直至运行到下面这行代码处为止,从这行代码上面的注释中,我们可以看到这块允许后置处理器来修改咱们这个bean的定义信息。

在这里插入图片描述

很明显,我们的bean实例创建完了以后,接下来就得来调用这个applyMergedBeanDefinitionPostProcessors方法了。

遍历获取到的所有后置处理器,若是MergedBeanDefinitionPostProcessor这种类型,则调用其postProcessMergedBeanDefinition方法

首先,按下F6快捷键让程序继续往下运行,直至运行到下面这行代码处为止,可以看到这儿调用了一个applyMergedBeanDefinitionPostProcessors方法。

在这里插入图片描述

那么,该方法又是来执行哪些后置处理器的呢?我们直接点击该方法进去它里面看一下,如下图所示,可以看到先是来获取到所有的后置处理器,然后再来遍历它们,如果是MergedBeanDefinitionPostProcessor这种类型的,那么就调用其postProcessMergedBeanDefinition方法。

在这里插入图片描述

从这儿也能看到,每一个后置处理器(或者说它里面的方法)的执行时机都是不一样的,比如我们在上一讲中所讲述的InstantiationAwareBeanPostProcessor这种类型的后置处理器中的两个方法的执行时机是在创建bean实例之前,而现在MergedBeanDefinitionPostProcessor这种类型的后置处理器,是在创建完bean实例以后,来执行它里面的postProcessMergedBeanDefinition方法的

所以说,如果大家要用到各种类型的后置处理器,那么你得清楚知道它们里面的方法是何时执行的,可一定要做到心中有数哟😁

接着,让程序继续往下运行,直至运行到下面这行代码处为止。

在这里插入图片描述

尼玛的,这儿又是来干嘛的啊😡?咱也不知道,咱也不敢问!不过从earlySingletonExposure变量的名字中,我们是不是能猜到这儿是来拿到什么单实例的要暴露的bean的呢?😔,我也不知道,只是猜测。

程序继续往下运行的过程中,我们发现其会进入到if判断语句中,来到addSingletonFactory方法处,如下图所示,调用该方法好像是来添加一些缓存的,咱也不必深究,直接略过。

在这里插入图片描述

于是,我们让程序继续往下运行,直至运行到下面这行代码处为止,很明显,populateBean方法是来为bean的属性赋值的。

在这里插入图片描述

也就是说,创建完bean实例以后,首先就是来为bean实例的属性赋值。

为bean实例的属性赋值

你可不要忘了程序现在依然还在doCreateBean方法内运行哟!在该方法内,首先会创建出我们的bean实例,然后再执行MergedBeanDefinitionPostProcessor这种类型的后置处理器,接着,创建完bean实例之后就得为其属性赋值了。

在这里插入图片描述

你有没有想过是如何为bean的属性赋值这一问题的呢?不急,我们不妨按下F5快捷键进入populateBean方法里面去看一下,如下图所示,可以看到一开始会拿到赋给所有属性的属性值。

在这里插入图片描述

只不过,我们现在没啥要赋的属性值,不信你看,但是如果有的话,那么就会拿到很多。

在这里插入图片描述

遍历获取到的所有后置处理器,若是InstantiationAwareBeanPostProcessor这种类型,则调用其postProcessAfterInstantiation方法

于是,我们让程序继续往下运行,直至运行到下面这行代码处为止,此时,大家可要注意了,现在依然还没有为bean的属性赋值哟!

在这里插入图片描述

可以看到,接下来会遍历获取到的所有后置处理器,如果是InstantiationAwareBeanPostProcessor这种类型的,那么就调用其postProcessAfterInstantiation方法。

而且,以上所有的这些操作均是在为bean的属性赋值之前做的哟~~~

再来遍历获取到的所有后置处理器,若是InstantiationAwareBeanPostProcessor这种类型,则调用其postProcessPropertyValues方法

我们继续按下F6快捷键让程序往下运行,直至遍历完所有的后置处理器,在这一过程中,傻子都能看出这一点,如果遍历出的后置处理器是InstantiationAwareBeanPostProcessor这种类型,那么就会调用其postProcessAfterInstantiation方法。

当程序运行到下面这行代码处时,好像是来拿到ResolvedAutowireMode这个东东的,咱也不知道这玩意是个嘛,咱也不敢问😄!只是在这记录一下。

在这里插入图片描述

继续让程序往下运行,你会发现程序并没有进入到if判断语句中,而是来到了下面这行代码处。

在这里插入图片描述

可以看到这儿调用了一个hasInstantiationAwareBeanPostProcessors方法,它是来判断是否有InstantiationAwareBeanPostProcessor这种类型的后置处理器的。

继续让程序往下运行,你会发现程序进入到了下面的if判断语句中,来到了下面这行代码处,这说明是有InstantiationAwareBeanPostProcessor这种类型的后置处理器的。

在这里插入图片描述

接着,继续让程序往下运行,很显然程序会再进入到下面的if判断语句中,因为确实是有InstantiationAwareBeanPostProcessor这种类型的后置处理器。

在这里插入图片描述

现在,你该对接下来所要做的事情了然于胸了吧!其实,就是遍历获取到的所有后置处理器,如果是InstantiationAwareBeanPostProcessor这种类型的,那么就调用其postProcessPropertyValues方法。

大家可要注意哟,即使是执行了InstantiationAwareBeanPostProcessor这种类型的后置处理器中的postProcessAfterInstantiation和postProcessPropertyValues这俩方法,咱们bean实例的属性依然还没有被赋值。那么,到底是啥时候来赋值的呢?

我们不妨让程序继续往下运行,直至遍历完所有的后置处理器。在这一过程中,我再说一遍啊,唉,都说的口都快干了,如果遍历出的后置处理器是InstantiationAwareBeanPostProcessor这种类型,那么就会调用其postProcessPropertyValues方法。

唉,对了,我们可以点进去InstantiationAwareBeanPostProcessor接口里面看一看它的源码哟,如下图所示,你可以看到它里面定义了一个postProcessPropertyValues方法,该方法会返回一个PropertyValues对象,它就是我们bean实例属性要被赋予的属性值,最终这些属性值会被赋值给bean的属性。我是这样理解的啦😂,也不知道对不对。

在这里插入图片描述

好像更加专业的说法是这样的,Spring获取bean的实例时,需要把配置的属性值解析到PropertyValues中,然后再填充入BeanWrapper。我在这里先记录一下。

当程序运行到下面这行代码处时,你会发现这儿调用了一个applyPropertyValues方法,这里才是正式开始为bean的属性赋值。

在这里插入图片描述

正式开始为bean的属性赋值

大家一定要注意啊,现在调用applyPropertyValues方法才是开始为bean的属性赋值,在为bean的属性赋值之前,我们知道会执行InstantiationAwareBeanPostProcessor这种类型的后置处理器中的postProcessAfterInstantiation和postProcessPropertyValues这俩方法。

其实,为bean的属性赋值,说到底就是利用setter方法为bean的属性进行赋值。这里,我们就不再进入applyPropertyValues方法去一探究竟了,它里面无非就是利用反射调setter方法之类的。

接下来,继续让程序往下运行,直至运行到下面这行代码处为止,此时,populateBean方法就执行完了,也就是说,已经为我们bean的属性赋完值了。

在这里插入图片描述

接着继续让程序往下运行,运行一步即可,这时程序来到了下面这行代码处。

在这里插入图片描述

可以看到,这儿调用了一个initializeBean方法,你是不是很熟悉它,因为我们之前就已经研究过它了,它就是来初始化bean的,下面我们再来详详细细地研究一下它。

至此,我们就知道了这样一个结论,为bean的属性赋完值之后,接着便要来初始化bean了。

初始化bean

至此,我们要不先梳理一下吧😊,你看我总结的可还行?

  • 1)在创建bean实例之前,会执行InstantiationAwareBeanPostProcessor这种类型的后置处理器中的两个方法,即postProcessBeforeInstantiation方法和postProcessAfterInitialization方法
  • 2)创建bean实例
  • 3)为bean实例的属性赋值。在赋值的过程中,会依次执行InstantiationAwareBeanPostProcessor这种类型的后置处理器中的两个方法,即postProcessAfterInstantiation方法和postProcessPropertyValues方法
  • 4)初始化bean

那么,你知不知道是如何来初始化bean的呢?我想你肯定不知道,不知道没关系,我们可以按下F5快捷键进入initializeBean方法中去一探究竟,如下图所示,进来之后,我们不妨让程序运行到下面这行代码处。

在这里插入图片描述

可以看到,这儿调用了一个invokeAwareMethods方法,顾名思义,它是来执行XxxAware接口中的方法的。

执行xxxAware接口的方法

对于XxxAware接口,不知你还有没有一些印象,我们以前就用过,比如我们之前曾经编写过这样一个Dog组件,如下所示,在该组件里面如果想要用IOC容器,那么就得让其实现ApplicationContextAware接口,这样,Spring就会在setApplicationContext方法中把IOC容器给传过来。

package com.meimeixia.bean;import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;/** * ApplicationContextAwareProcessor这个类的作用是可以帮我们在组件里面注入IOC容器, * 怎么注入呢?我们想要IOC容器的话,比如我们这个Dog组件,只需要实现ApplicationContextAware接口就行 *  * @author liayun * */@Componentpublic class Dog implements ApplicationContextAware {
private ApplicationContext applicationContext; public Dog() {
System.out.println("dog constructor..."); } // 在对象创建完成并且属性赋值完成之后调用 @PostConstruct public void init() {
// 在这儿打个断点调试一下 System.out.println("dog...@PostConstruct..."); } // 在容器销毁(移除)对象之前调用 @PreDestroy public void destory() {
System.out.println("dog...@PreDestroy..."); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// 在这儿打个断点调试一下 // TODO Auto-generated method stub this.applicationContext = applicationContext; } }

那么,在invokeAwareMethods方法中是怎么来执行XxxAware接口的方法的呢?我们不妨按下F5快捷键进入该方法里面去看一下,如下图所示。

在这里插入图片描述

可以看到,它就是来判断我们的bean是不是实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware这些Aware接口的,若是则回调接口中对应的方法。

当然了,现在我们的bean(即Blue对象)是没有实现以上这些Aware接口的,所以,我们直接让程序继续往下运行,直至运行到下面这行代码处为止。

在这里插入图片描述

执行后置处理器初始化之前的方法(即postProcessBeforeInitialization方法)

执行完XxxAware接口中的方法之后,可以看到会再来调用一个applyBeanPostProcessorsBeforeInitialization方法,该方法我们之前也研究过,不是吗?

那么,你知道applyBeanPostProcessorsBeforeInitialization方法中具体执行了哪些逻辑吗?我们不妨按下F5快捷键进入该方法里面去看一下,如下图所示。

在这里插入图片描述

可以看到,在applyBeanPostProcessorsBeforeInitialization方法中,会遍历所有的后置处理器,然后依次执行所有后置处理器的postProcessBeforeInitialization方法,一旦后置处理器的postProcessBeforeInitialization方法返回了null以后,则后面的后置处理器便不再执行了,而是直接退出for循环。

然后,我们让程序继续往下运行,一直运行到下面这行代码处为止。

在这里插入图片描述

现在,你该知道后置处理器初始化之前的方法(即postProcessBeforeInitialization方法)的调用时机了吧😁

执行初始化方法

执行完后置处理器的postProcessBeforeInitialization方法之后,可以看到现在又调用了一个invokeInitMethods方法,其作用就是执行初始化方法。

哎呀,初始化方法究竟是指哪些方法呢?我们不妨来回顾一下,是不是包括了一个实现InitializingBean接口的方法啊?还记得我们之前曾经编写过如下所示这样一个Cat组件吗?

package com.meimeixia.bean;import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.InitializingBean;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Component;// @Scope("prototype")@Componentpublic class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("cat constructor..."); } /** * 会在容器关闭的时候进行调用 */ @Override public void destroy() throws Exception {
// TODO Auto-generated method stub System.out.println("cat destroy..."); } /** * 会在bean创建完成,并且属性都赋好值以后进行调用 */ @Override public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub System.out.println("cat afterPropertiesSet..."); }}

可以看到,以上Cat组件实现了一个InitializingBean接口,而该接口中定义了一个afterPropertiesSet方法,必然在Cat组件内就会实现该方法,这样,该方法就是Cat组件的初始化方法了。

当然了,我们除了通过以上方式来指定初始化方法之外,还可以在@Bean注解中使用initMehod属性来指定初始化方法,就像下面这样。

package com.meimeixia.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Scope;import com.meimeixia.bean.Car;/** *  * @author liayun * */@ComponentScan("com.meimeixia.bean")@Configurationpublic class MainConfigOfLifeCycle {
// @Scope("prototype") @Bean(initMethod="init", destroyMethod="destroy") public Car car() {
return new Car(); } }

从以上配置类的代码中可以看出,我们指定了Car对象中的init方法为初始化方法,destroy方法为销毁方法,而Car类的代码如下所示。

package com.meimeixia.bean;import org.springframework.stereotype.Component;@Componentpublic class Car {
public Car() {
System.out.println("car constructor..."); } public void init() {
System.out.println("car ... init..."); } public void destroy() {
System.out.println("car ... destroy..."); } }

好,回顾完了,我们现在将记忆拉到现实,来看一下究竟是如何来执行初始化方法的。于是,我们按下F5快捷键进入invokeInitMethods方法里面去看一下,如下图所示。

在这里插入图片描述

可以看到,一开始就会来判断我们的bean是否是InitializingBean接口的实现,若是则执行该接口中定义的初始化方法。

如果不是的话呢?我们不妨继续让程序往下运行,可以发现程序并没有进入到下面的if判断语句中,而是来到了下面这行代码处,这是因为我们的bean并没有实现InitializingBean接口。

在这里插入图片描述

这时,是来看我们的bean是否自定义了初始化方法,如果是的话,那么就来执行初始化方法。

但是,现在我们的bean是没有自定义初始化方法的,因此在程序继续往下运行的过程中,程序并不会进入到下面的if判断语句中,而是来到了下面这行代码处。

在这里插入图片描述

此时,invokeInitMethods方法便执行完了。这其实就是说,Spring会帮我们把我们bean中的初始化方法回调一下。

执行后置处理器初始化之后的方法(即postProcessAfterInitialization方法)

初始化方法执行完了以后,下一步就是来调用applyBeanPostProcessorsAfterInitialization方法,难道不是这样吗?

在这里插入图片描述

那么,你知道applyBeanPostProcessorsAfterInitialization方法中具体执行了哪些逻辑吗?我们不妨按下F5快捷键进入该方法里面去看一下,如下图所示。

在这里插入图片描述

可以看到,在applyBeanPostProcessorsAfterInitialization方法中,会遍历所有的后置处理器,然后依次执行所有后置处理器的postProcessAfterInitialization方法,一旦后置处理器的postProcessAfterInitialization方法返回了null以后,则后面的后置处理器便不再执行了,而是直接退出for循环。

然后,我们让程序继续往下运行,一直运行到下面这行代码处为止,可以看到我们的bean已经初始化完了。

在这里插入图片描述

以上就是我们bean的整个初始化逻辑。

我们的bean初始化完了以后,继续让程序往下运行,直至运行到下面这行代码处为止,很显然,这儿是来获取我们单实例bean的,因为我们单实例bean都已经创建好了。

在这里插入图片描述

不错,这儿确实是来获取我们单实例bean的,只不过是先从缓存中来获取,但缓存中还没有我们bean呢。妈的,老子Inspect了一下bean变量的值,如下图所示,发现我们的bean确实是已经创建好了。

在这里插入图片描述

好吧,从缓存中获取不到就获取不到吧,我们就让程序继续往下运行,很显然程序是不会进入到下面的if判断语句中的,而是来到了这行代码处。

在这里插入图片描述

可以看到这儿调用了一个registerDisposableBeanIfNecessary方法,那么该方法又是来干嘛的呢?

注册bean的销毁方法

现在程序是不是又回到了doCreateBean方法中了呢?确实是哟!那么,registerDisposableBeanIfNecessary方法是来干嘛的呢?它是来注册我们bean的销毁方法的。注意,这里只是注册而不是调用哟😊

我们知道,销毁方法是在IOC容器关闭以后才被调用的。还记得,我们之前是如何指定销毁方法的吗?聪明的同学一定知道,因为上面的那个Cat组件就实现了一个DisposableBean接口,因此该组件里面的destroy方法就是销毁方法,它会在容器关闭的时候进行调用。

我们不妨按下F5快捷键进入registerDisposableBeanIfNecessary方法里面去看一下,如下图所示,看一下而已,没必要深究,因为这一块呢,只是提前把bean的销毁方法注册了一下。

在这里插入图片描述

然后,继续让程序往下运行,直至运行到下面这行代码处为止,此时,doCreateBean方法就算是返回了一个bean实例。

在这里插入图片描述

我们经过以上这么多的步骤,终于终于将bean实例创建出来了,是不是很不容易啊!你可能要问了,经过了哪些步骤啊?能不能给总结一下呢?其实,这些步骤都包含在以上doCreateBean方法中,我不妨总结一下。

  • 1)在创建bean实例之前,会执行InstantiationAwareBeanPostProcessor这种类型的后置处理器中的两个方法,即postProcessBeforeInstantiation方法和postProcessAfterInitialization方法
  • 2)创建bean实例
  • 3)为bean实例的属性赋值。在赋值的过程中,会依次执行InstantiationAwareBeanPostProcessor这种类型的后置处理器中的两个方法,即postProcessAfterInstantiation方法和postProcessPropertyValues方法
  • 4)初始化bean,而且在初始化前后会执行后置处理器中的两个方法,即postProcessBeforeInitialization方法和postProcessAfterInitialization方法
  • 5)注册bean的销毁方法

经过上面这些繁琐的步骤,咱们的bean就创建出来了。

于是,我们继续让程序往下运行,先运行到下面这行代码处,这时,createBean方法就算是彻底执行完了,而且它会返回创建好的bean实例哟~

在这里插入图片描述

然后,再运行到下面这行代码处,这时,就能获取到创建出的bean实例了。

在这里插入图片描述

真的是这样吗?我们不妨Inspect一下singletonObject变量的值,如下图所示,发现我们的bean实例(即Blue对象)确实是被获取到了。

在这里插入图片描述

接着,让程序运行到下面这行代码处,可以看到,这儿会调用一个addSingleton方法,那么,该方法又干了些啥呢?

在这里插入图片描述

将创建出的单实例bean添加到缓存中

当我们的单实例bean创建出来之后,接下来就得调用一个addSingleton方法了,该方法的作用就是将创建的单实例bean添加到缓存中。

现在,你是不是能得出这样一个结论了,只要单实例bean创建出来了,那么就会将其添加到缓存中

我们可以按下F5快捷键进入addSingleton方法里面去看一下,如下图所示,你还记得singletonObjects吗?

在这里插入图片描述

笨蛋,上一讲我们就已讲解过了,singletonObjects是DefaultSingletonBeanRegistry类里面的一个属性,点它,你就能看到了,如下图所示。

在这里插入图片描述

可以看到singletonObjects属性就是一个Map集合,该Map集合里面缓存的就是所有的单实例bean,而且还是按照bean的名字和其实例对象缓存起来的,这可以从该属性上面的注释中看出来。

哦,原来缓存就是一个Map集合啊😀,那么,将创建的单实例bean添加到缓存中指的不就是将创建的单实例bean添加到singletonObjects指代的Map集合中吗?第一次获取单实例bean,就是从singletonObjects里面来获取的,你还记得吗?

将创建的单实例bean添加到singletonObjects指代的Map集合中,好处是以后我们就可以直接从这个Map集合里面来获取了。

现在,你该知道什么叫IOC容器了吧!所谓的IOC容器就是指各种各样的Map集合,而且这些Map集合有很多哟😋,如下图所示,这些Map集合里面保存了我们创建的所有组件以及IOC容器的其他信息。

在这里插入图片描述

也就是说,以上所有这些Map集合就构成了Spring的IOC容器,容器里面保存了所有的组件。以后,我们从容器中来获取组件,其实就是从这些Map集合里面来获取组件。

好了,单实例bean的创建流程我们就算是完完整整地过了一遍了。

接下来,我们继续让程序往下运行,直至运行到下面这行代码处为止,至此,我们的单实例bean就获取到了。

在这里插入图片描述

然后,让程序往下运行到下面这行代码处,可以看到这儿将会返回我们获取到的单实例bean。

在这里插入图片描述

接着,让程序往下运行到下面这行代码处,可以看到getBean方法总算是执行完了,这时,也就获取到了我们的单实例bean。

在这里插入图片描述

此时,程序停留在了第764行代码处!

转载地址:https://liayun.blog.csdn.net/article/details/114480958 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Spring注解驱动开发第48讲——Spring IOC容器创建源码解析(八)之完成BeanFactory的初始化创建工作,最终完成容器创建
下一篇:Spring注解驱动开发第46讲——Spring IOC容器创建源码解析(六)之初始化所有剩下的单实例bean(上)

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月18日 15时41分45秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章