Spring IOC容器初始化原理分析 (第六节中)

「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

1.前言

本文主要是续讲Spring IOC容器初始化原理分析 (第六节上),在本篇文章中我们主要详细讲一下 preInstantiateSingletons()中的 getBean(String name) 方法和 AccessController.doPrivileged()方法,这里preInstantiateSingletons()中别的方法已经分析过了,感兴趣的可以看一下。

2.getBean(String name)

老样子我们直接先贴源码

图片.png
可以发现他这里面就直接调了一个 doGetBean() 方法,那我们接着往下看,这个方法有点长,那我们先看一下方法的简介:

图片.png

主要作用:返回指定bean的一个实例,该实例可以是共享的,也可以是独立的。
参数简介:

  • name: 要检索的bean的名称
  • requiredType :要检索的bean的类型
  • args : 建bean实例时使用的Args参数(仅在创建时使用)
  • typeCheckOnly :是否进行类型检查

这里鉴于代码太长了 我就一块块截取下来给大家分析

1.doGetBean第一块代码

图片.png

  1. ransformedBeanName:返回bean名称,必要时去掉工厂解引用前缀,并将别名解析为规范名称。这里返回的处理后的name是直接对应singletonObjects中的key。
  2. getSingleton(beanName) 在上一篇文章 4.3中我详细讲过,感兴趣的话大家可以去看一看,它的主要作用拿到这个单例bean,第一次进来的时候 sharedInstance 肯定为空!
  3. isSingletonCurrentlyInCreation(beanName):返回指定的单例bean当前是否正在创建中
    图片.png
    图片.png
  4. getObjectForBeanInstance():前面返回的 sharedInstance 是最初始的bean,不一定使我们想要的,获取给定bean实例的对象,可以是bean实例本身,也可以是FactoryBean中创建的对象。

图片.png

  • 这里首先判断name 是不是以‘&’开头,如果是说明它是一个FactoryBean的name 判断当 beanInstance instanceof Nullbean 时 直接返回,当它不 属于 FactoryBean 时抛出异常
  • 这里name不是以 ‘&’ 开头, 当它不是 FactoryBean 时直接返回。
  • 当它是 FactoryBean接着往下看,从FactoryBean单例对象缓存中尝试获取它,若不为空,直接返回
  • 强转为FactoryBean,上面已经判断过,此时一定是FactoryBean类型。
    • 当mbd == null ,切保存BeanDefinition的map中可以取到这个 beanName 的BeanDefinition时,调用getMergedLocalBeanDefinition(beanName)
    • 判断mdb是否为空,以及检测是不是系统创建的,然后调用 getObjectFromFactoryBean()方法 (ps:从给定的 Factory 中获取指定的bean 后续有时间再讲这个)

第一块的主要作用就是:当 sharedInstance != null 且 args == null 时获取bean 对象

2.doGetBean第二块代码

图片.png

接着往下看,前面处理sharedInstance != null 且 args == null的情况,这里处理其余情况。

  1. isPrototypeCurrentlyInCreation(beanName),检查是否存在原型模式下的循环依赖,如果存在直接抛异常,spring 解决不了,原型模式下的循环依赖。
    图片.png
    图片.png
    rototypesCurrentlyInCreation 保存的是原型模式正在创建的对象,当它中包含这个beanName 说明存在循环依赖,单例模式下的循环依赖如何解决
  2. 检查当前容器中是否存在指定名称的 beanDefinition
  • 先取得当前容器的父容器不为null 且 保存beanDefinition的Map中取不到 该beanName 对应的 beanDefinition。
  • 解析该beanName 的原始名字
  • 当 parentFactory instanceof AbstractBeanFactory 时,即递归的去父级容器中寻找
  • 否则 当 args 不为null 时,委派父级容器根据名称和参数寻找
  • 否则 当 requiredType 不为 null 时,委派父级容器根据 名称和类型找
  • 否则 委派父级跟剧名称找
  1. typeCheckOnly:是否需要类型检查,不需要时进入
    图片.png
    图片.png

图片.png
这部分代码,主要是当不需要类型判断时,向容器中标记指定的bean被创建。

  • this.aredyCreated : 保存已经创建的bean的name
  • this.mergedBeanDefinitions : 保存 beanName –> RootBeanDefinition

3.doGetBean 第三块代码

图片.png

  1. 首先获取其父类Bean定义,子类合并父类公共属性,getMergedLocalBeanDefinition在上篇文章4.1中讲过,然后检查给定的合并bean定义
    图片.png
  2. mbd.getDependsOn():获取当前Bean依赖的Bean的名称,当它不为null时,取出每一个依赖的bean
    图片.png
    图片.png
    isDependent(beanName,dependentBeanName):检查依赖名为 beanName 的这个bean 依赖的beans 是否有名为dependentBeanNamed,(即判断 dependentBeanName 是否依赖 beanName)
    • alreadySeen : 已经检查过的,这里保存的是所有检查过的beanName
    • 若当前 beanName 已在 alreadySeen 中 直接返回false,否则的话 取出依赖它的的beans的名字集合(即 dependentBeans)
    • 若 dependentBeans 包含 dependentBeanName 返回true ,否则遍历 dependentBeans,把beanName 加到 alreadySeen 中去,递归判断 dependentBeanName 是否依赖 dependentBeans中的每一个beanName
    • 当它存在这种循环依赖时,抛出异常,这也是为啥单例模式构造器相互依赖spring 解决不了的原因
  3. registerDependentBean(dep, beanName):为指定的bean注入依赖的bean
    • dep: 指定的bean
    • beanName: 依赖的bean
    • this.dependentBeanMap : 保存的是依赖指定bean 的 beanNames 集合
    • this.dependenciesForBeanMap : 保存的是指定bean 所依赖的 beanNames 集合
      图片.png
      图片.png
  • 先锁定 this.dependentBeanMap,从这里面取得key为 canonicalName,若为null,则new一个LinkedHsahSet。 把 dependentBeanName 加入进去。(这里实际是当我们在创建当前bean时,会在bean依赖的bean 所对应的 this.dependentBeanMap 中把 当前bean加进去)
  • 然后锁定 this.dependenciesForBeanMap ,这里实际是,把当前创建的bean 的 this.dependenciesForBeanMap 更新一下,加入它依赖的 canonicalName
  1. getBean(dep)
  • dep:当前创建的bean 依赖的bean,这里是先去创建它。

4. doGetBean 第四块代码

这一部分代主要完成bean的实例化,本来想这篇文章讲完的,但是如果想讲的细的话,实在太多了,所以这篇文章主要讲大概的,下篇文章我会详细的研究这块的代码
图片.png

  • 首先判断它是不是单例的,如果是则完成单例对象实例化
  • 判断是不是模型模式,若是则每次都会新建一个对象
  • 否则,获取它的作用域,也是创建一个实例对象返回出去

5. doGetBean 第五块代码

图片.png
图片.png

  1. 这里主要是进行类型检查 isInstance(Object obj) 是 Class类的一个本地方法,主要用来检查bean能否强转成 requiredType 类型的方法
  2. 当requiredType 不为null 且bean不能转换成 requiredType 时

图片.png

  • 获取类型转换器,先获取用户自己定义的,如果没有,则 spring 会返回默认的 SimpleTypeConverter 类型转换器。
    图片.png
  • convertIfNecessary(bean,requiredType): 把bean转成 requiredType 类型,这里如果是自定义的则,需要实现该接口,重写该方法。如果是默认的 SimpleTypeConverter 类型转换器,调用的是:org.springframework.beans.TypeConverterSupport#convertIfNecessary(java.lang.Object, java.lang.Class),这个后面有时间可以再额外讲一下
  1. 若转换成功则返回该bean,若转换失败,则抛出异常。

总结:这里getBean(name) 方法算是讲完了,总结起来就是,获取该bean 实例。

  1. AccessController.doPrivileged(PrivilegedAction action,AccessControlContext context)

图片.png
这个方法我的理解就是,用于获取特权,绕过java的权限检查,它在 preInstantiateSingletons() 中出现两处。

2021-11-15_165047.jpg

4.总结

今天就先写到这里,下篇文章主要讲,前面提到的 单例模式,原型模式,其他scope 对象创建的具体细节。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%