「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」
1.前言
本文主要讲Spring IOC容器初始化过程中的 finishBeanFactoryInitialization(beanFactory) 方法,如想看之前的内容可查看 Spring IOC容器初始化原理分析 (第五节)
finishBeanFactoryInitialization(beanFactory) 是在Spring IOC 容器初始化过程中 refresh()中调用的,它的主要作用是实例化所有非懒加载的单实例bean
2.refresh()源码
如果需要复制代码,可前往Spring IOC容器初始化原理分析 (第一节)
3.finishBeanFactoryInitialization(beanFactory) 源码
3.1 第一步详解
这里先把变量的源码贴一下
所以到这里 第一步的作用就很简单明了了,先判断 beanFactory 中 是否包含一个名为 conversionService 的bean 且 它的类型是 ConversionService.class 如果有的话,就把它设置到 beanFactory 的 conversionService属性中去。 ConversionService.class是一个用于系统类型转换的接口,我们可以实现它,自定义一些类型转换方式。
3.2 第二步详解
hasEmbeddedValueResolver 的默认实现如下图
其实这步的主要作用就是判断 embeddedValueResolvers 中是否有 StringValueResolver 对象,如果没有的话,给它注册一个默认的 StringValueResolver 对象,这里StringValueResolver 的作用主要用用来解析注解中字符串的属性值。
3.3第三步详解
这步的主要作用就是,初始化所有的 LoadTimeWeaverAware ,以便尽早的注册它们的转换器。LoadTimeWeaverAware 的主要作用是 在加载sring bean 织入第三方模块,这和spring aop 相关。这里就先不细讲了,想了解的话大家可以官网扒一扒。
3.4 第四步详解
这步作用比较直接:停止使用临时类加载器进行类型匹配,即把临时类型加载器设为null
3.5 第五步详解
缓存所有的bean定义的元数据,不希望后面还修改,即bean 即将被实例化,不希望它的数据被修改。源码如下:
4.preInstantiateSingletons() (第六步)
这步的作用就是实例化所有剩余的 非懒加载的单实例bean,接下来我们一步步分析下它的实例化过程
1 | scss复制代码public void preInstantiateSingletons() throws BeansException { |
4.1 getMergedLocalBeanDefinition(beanName) 方法
在讲这个方法前,先简单了解一下 BeanDefintion,Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。 BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息以及bean 的作用域,是否懒加载等 创建这个bean 所需要的所有信息。这里我就简单说一下。
- AbstractBeanDefinition:抽象类,实现了BeanDefinition的部分方法。方便子类继承
- AnnotatedBeanDefinition:注解类型的 BeanDefinition
- RootBeanDefinition:父级 BeanDefinition
- ChildBeanDefinition:子级 BeanDefinition,必须设置 parentName 即父级 BeanDefinition的信息
- GenericBeanDefinition:一般的 BeanDefinition
mergedBeanDefinitions:hashMap key是beanName,value是 RootBeanDefinition
这个方法的官方定义是:返回合并的RootBeanDefinition,如果指定的bean对应于子bean定义,则遍历父bean定义。
这里先取到 RootBeanDefinition mbd,判断当他,不为空,且不需要重新合并定义的时候直接返回(ps: 这里的stale表示是否需要是否需要重新合并定义)
否则的话调用
首先先说一下 getBeanDefinition(beanName) :即根据名称从 beanDefinitionMap 取出对应 BeanDefinition
接着再来讲getMergedBeanDefinition(beanName, getBeanDefinition(beanName))
接着往下追
1 | scss复制代码protected RootBeanDefinition getMergedBeanDefinition( |
图一(多张):
图二(多张):
这里实际是通过 得到的 parentBeanName ,先判断当容器中的 beanDefinitionMap不包含它时且
this.parentBeanFactory instanceof ConfigurableBeanFactory 时 在调用本身。否则的话
再走一遍4.1的流程
图三:
图四:
4.2 isFactoryBean(beanName) 源码如下
1.先取得最终的beanName,然后拿着这个名字,调用getSingleton(beanNama,false)方法,返回单例对象。
这里 getSingleton 在 4.3 中有详细讲到
- beanInstance 不为null 时直接返回 beanInstance instanceof FactoryBean ,否则的话就说明这个beanName对应的bean还没有实例化,则先判断当容器中的 beanDefinitionMap不包含它时且 this.parentBeanFactory instanceof ConfigurableBeanFactory 时 接着判断。
3.isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName))
先取出 mbd的isFactoryBean,当它不是null的时候直接返回,否则调用 predictBeanType
- predictBeanType:获取 targetType
- getTargetType: 如果已知,返回此bean定义的目标类型,当根据它的 targetType 返回
如果targetType 不为null 直接返回,否则的话 判断 this.factoryMethodName 不为空时返回resolveBeanClass(mbd, beanName, typesToMatch),这个方法的主要作用:解析指定bean定义的bean类,将bean类名解析为class引用(如果需要),并将解析后的class存储在bean定义中以供进一步使用。这里就不往下继续讲了
- getTargetType: 如果已知,返回此bean定义的目标类型,当根据它的 targetType 返回
4.3 getSingleton(beanName)
主要作用: 获取该beanName 下注册的单实例对象。
源码如下:
this.singletonObjects(一级缓存)是一个Map 缓存了所有实例化好的单例对象,对象名–》对象,从里面拿出这个对象。
- 如果不为null,则直接返回。
- 否则判断当前正在创建的bean中是否有它(this.singletonsCurrentlyInCreation 保存当前正在创建的对象的名称,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或者在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)
- 如果没有直接返回
- 如果有则从this.earlySingletonObjects(二级缓存,保存提前曝光的单例对象:beanName –>bean实例) 中取出
- 当 allowEarlyReference=false 直接返回.
- 否则从 this.singletonFactories (三级缓存,保存的是要被实例化的对象的对象工厂 beanName –> ObjectFactory):取出 ObjectFactory 当它不为空的时候 从这里面取到 singletonObject,顺便把它从 singletonFactories 中移除,把它添加到 earlySingletonObjects 中,最终返回 singletonObject.
这里这种设计思想(三级缓存),实际上帮我们解决,单例模式下setter循环依赖的问题(即通过属性相互依赖的问题,构造器依赖spring解决不了)
例如有两个类,A和B ,A中有个属性是B,B中有个属性是A,spring 在初始的时候,先初始A 对象,当A完成初始化的第一步时(此时构造器放在已经执行完成),spring 会将它放在 singletonFactories 中 (具体的初始化过程下篇再讲),然后准备继续往下执行的时候,A 发现 它依赖B对象,A会从容器中尝试获取B,当A没有获取到的时候,就会转而先去创建B对象,B执行完构造器方法后,接着往下执行,发现自己依赖A。于是尝试获取A,从
一级缓存singletonObjects中获取(没有,因为A还没初始化完全),从二级缓存earlySingletonObjects中获取
(也没有),尝试三级缓存singletonFactories中获取,因为A通过ObjectFactory将自己提前曝光了,所以B可以获取到A(虽然没有初始化完全,但是能获取到),然后B完成自己的初始化过程,然后A接着完成自己的初始化过程
5.小结
本来想一篇弄完的,结果发现东西太多了,下篇文章我在继续补,下篇文章主要讲这个的后续的 4.3 getBean()和后面的方法。
本文转载自: 掘金