Sping源码(九)—— Bean的初始化(非懒加载)— getMergedLocalBeanDefinition

本文主要是介绍Sping源码(九)—— Bean的初始化(非懒加载)— getMergedLocalBeanDefinition,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

序言

前两篇文章介绍了Bean初始化之前的一些准备工作,包括设置BeanFacroty的ConversionService属性以及将Bean进行冻结。这篇文章将会进入到preInstantiateSingletons方法。进一步了解Bean的初始化流程。

preInstantiateSingletons

	public void preInstantiateSingletons() throws BeansException {// 将所有BeanDefinition的名字创建一个集合List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...// 触发所有非延迟加载单例bean的初始化,遍历集合的对象for (String beanName : beanNames) {// 合并父类BeanDefinitionRootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);//省略部分代码....}}

分析

遍历BeanDefinitionName首先做的第一步是合并父类的beanDefinition。
合并过程大致可以分为以下几个步骤:

  1. mergedBeanDefinitions缓存中获取,缓存中有且不需要重新合并定义,则return
  2. 如果 containingBd 为null,则再次从缓存mergedBeanDefinitions中获取。
  3. 如果缓存中依然没有或者需要重新定义。
    3.1 获取parentName,如果parentName = null则创建(克隆)一个RootBeanDefinition封装当前Bean。
    3.2 parentName != null , 且当前beanName = parentName ,使用父工厂获取parentBeanName对应的合并BeanDefinition赋值给父BeanDefinition
    3.3 parentName != null , 且当前beanName != parentName , 如果父类尚未被加载,且父工厂属于ConfigurableBeanFactory
    调用父工厂进行merge操作。

源码

源码中涉及到很多方法的重载和重写,阅读源码时还要仔细分清。
getMergedLocalBeanDefinition
先尝试从缓存中拿。

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {// Quick check on the concurrent map first, with minimal locking.//先尝试从mergedBeanDefinitions缓存中取RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);//如果缓存中有 && 不需要重新合并定义 则直接returnif (mbd != null && !mbd.stale) {return mbd;}//获取 beanName对应的合并BeanDefinition,如果是ChildBeanDefinition 则需要合并return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));}

getMergedBeanDefinition
整体流程步骤上面大致已经介绍。

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)throws BeanDefinitionStoreException {synchronized (this.mergedBeanDefinitions) {RootBeanDefinition mbd = null;RootBeanDefinition previous = null;// Check with full lock now in order to enforce the same merged instance.// 先尝试从mergedBeanDefinitions缓存中取if (containingBd == null) {mbd = this.mergedBeanDefinitions.get(beanName);}if (mbd == null || mbd.stale) {previous = mbd;//parentName为null,说明没有父类BeanDefinition需要合并if (bd.getParentName() == null) {// Use copy of given root bean definition.//如果当前的bd是RootBeanDefinition 则直接克隆if (bd instanceof RootBeanDefinition) {mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();}else {//否则则创建RootBeanDefinitionmbd = new RootBeanDefinition(bd);}}else {// Child bean definition: needs to be merged with parent.//parentName不为null,则需要合并BeanDefinition pbd;try {//通过transformedBeanName方法获取parentBean的最终别名String parentBeanName = transformedBeanName(bd.getParentName());//如果当前beanName不等于parentBeanNameif (!beanName.equals(parentBeanName)) {// 获取parentBeanName的"合并的"BeanDefinition赋值给pdbpbd = getMergedBeanDefinition(parentBeanName);}else {//如果当前beanName等于parentBeanName,则获取父类工厂BeanFactory parent = getParentBeanFactory();//如果父类工厂是ConfigurableBeanFactory,则使用父工厂获取parentBeanName对应的合并BeanDefinition赋值给pdbif (parent instanceof ConfigurableBeanFactory) {pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);}}}// Deep copy with overridden values.//生成RootBeanDefinitionmbd = new RootBeanDefinition(pbd);mbd.overrideFrom(bd);}// Set default singleton scope, if not configured before.//设置默认的scopeif (!StringUtils.hasLength(mbd.getScope())) {mbd.setScope(SCOPE_SINGLETON);}if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {mbd.setScope(containingBd.getScope());}//暂时缓存合并的bean定义(稍后可能仍会重新合并以获取元数据更正),如果没有传入包含bean定义 且 当前工厂是同意缓存bean元数据//cacheBeanMetadata:默认为true 代表是缓存bean元数据,还是在每次访问时重新获取它if (containingBd == null && isCacheBeanMetadata()) {this.mergedBeanDefinitions.put(beanName, mbd);}}if (previous != null) {copyRelevantMergedBeanDefinitionCaches(previous, mbd);}return mbd;}}

getMergedBeanDefinition
父类调用的((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);

public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {//获取实际的beanNameString beanName = transformedBeanName(name);// Efficiently check whether bean definition exists in this factory.// 当前beanName在当前工厂的beanDefinitionMap中不存在 && 父工厂 属于 ConfigurableBeanFactoryif (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {//使用父工厂返回beanName的合并BeanDefinition【如有必要,将子bean定义与其父级合并】return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);}// Resolve merged bean definition locally.//本地解决合并的bean定义return getMergedLocalBeanDefinition(beanName);}

流程图

在这里插入图片描述

总结

总结:
没有父类就创建一个RootBeanDefinition封装信息、放入缓存后返回。
有父类则调用父类工厂进行merge操作后,同样创建RootBeanDefinition封装父类信息后返回给子类,子类拿到父类返回的BeanDefinition后再次封装进RootBeanDefinition,设置信息后、放入缓存返回。

值得一提的是mergedBeanDefinitions变量,在Spring中有很多类似的应用,将不太变化且经常可以用到的东西放入缓存中,用时先在缓存中获取,包括beanDefinitionMap等变量都是如此。

mergedBeanDefinitions变量其实我们并不是第一次见到,源码中在执行invokeBeanFactoryPostProcessors方法时,会调用beanFactory.getBeanNamesForType方法获取系统中实现了BeanFactoryPostProcessorBeanDefinitionRegistoryPostProcessor的类。

beanFactory.getBeanNamesForType方法中就有beaDefinition的merge操作,感兴趣可以再了解了解。

这篇关于Sping源码(九)—— Bean的初始化(非懒加载)— getMergedLocalBeanDefinition的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1014209

相关文章

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

springboot加载不到nacos配置中心的配置问题处理

《springboot加载不到nacos配置中心的配置问题处理》:本文主要介绍springboot加载不到nacos配置中心的配置问题处理,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录springboot加载不到nacos配置中心的配置两种可能Spring Boot 版本Nacos

Spring中管理bean对象的方式(专业级说明)

《Spring中管理bean对象的方式(专业级说明)》在Spring框架中,Bean的管理是核心功能,主要通过IoC(控制反转)容器实现,下面给大家介绍Spring中管理bean对象的方式,感兴趣的朋... 目录1.Bean的声明与注册1.1 基于XML配置1.2 基于注解(主流方式)1.3 基于Java

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

IDEA下"File is read-only"可能原因分析及"找不到或无法加载主类"的问题

《IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题》:本文主要介绍IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题,具有很好的参... 目录1.File is read-only”可能原因2.“找不到或无法加载主类”问题的解决总结1.File

8种快速易用的Python Matplotlib数据可视化方法汇总(附源码)

《8种快速易用的PythonMatplotlib数据可视化方法汇总(附源码)》你是否曾经面对一堆复杂的数据,却不知道如何让它们变得直观易懂?别慌,Python的Matplotlib库是你数据可视化的... 目录引言1. 折线图(Line Plot)——趋势分析2. 柱状图(Bar Chart)——对比分析3

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

在 PyQt 加载 UI 三种常见方法

《在PyQt加载UI三种常见方法》在PyQt中,加载UI文件通常指的是使用QtDesigner设计的.ui文件,并将其转换为Python代码,以便在PyQt应用程序中使用,这篇文章给大家介绍在... 目录方法一:使用 uic 模块动态加载 (不推荐用于大型项目)方法二:将 UI 文件编译为 python 模

C++类和对象之初始化列表的使用方式

《C++类和对象之初始化列表的使用方式》:本文主要介绍C++类和对象之初始化列表的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C++初始化列表详解:性能优化与正确实践什么是初始化列表?初始化列表的三大核心作用1. 性能优化:避免不必要的赋值操作2. 强

SpringIOC容器Bean初始化和销毁回调方式

《SpringIOC容器Bean初始化和销毁回调方式》:本文主要介绍SpringIOC容器Bean初始化和销毁回调方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录前言1.@Bean指定初始化和销毁方法2.实现接口3.使用jsR250总结前言Spring Bea