Spring源码剖析4:懒加载的单例Bean获取过程分析
本文转自五月的仓颉 https://www.cnblogs.com/xrq730
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
喜欢的话麻烦点下Star哈
文章将同步到我的个人博客:
www.how2playlife.com
本文是微信公众号【Java技术江湖】的《Spring和SpringMVC源码分析》其中一篇,本文部分内容来源于网络,为了把本文主题讲得清晰透彻,也整合了很多我认为不错的技术博客内容,引用其中了一些比较好的博客文章,如有侵权,请联系作者。
该系列博文会告诉你如何从spring基础入手,一步步地学习spring基础和springmvc的框架知识,并上手进行项目实战,spring框架是每一个Java工程师必须要学习和理解的知识点,进一步来说,你还需要掌握spring甚至是springmvc的源码以及实现原理,才能更完整地了解整个spring技术体系,形成自己的知识框架。
后续还会有springboot和springcloud的技术专题,陆续为大家带来,敬请期待。
为了更好地总结和检验你的学习成果,本系列文章也会提供部分知识点对应的面试题以及参考答案。
如果对本系列文章有什么建议,或者是有什么疑问的话,也可以关注公众号【Java技术江湖】联系作者,欢迎你参与本系列博文的创作和修订。
前言
xml的读取应该是Spring的重要功能,因为Spring的大部分功能都是以配置做为切入点的。
我们在静态代码块中读取配置文件可以这样做:
//这样来加载配置文件
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
(1)XmlBeanFactory 继承 AbstractBeanDefinitionReader ,使用ResourceLoader 将资源文件路径转换为对应的Resource文件。
(2)通过DocumentLoader 对 Resource 文件进行转换,将 Resource 文件转换为 Document 文件。
(3)通过实现接口 BeanDefinitionDocumentReader 的 DefaultBeanDefinitionDocumentReader 类对Document 进行解析,并且使用 BeanDefinitionParserDelegate对Element进行解析。
step1:

在平常开发中,我们也可以使用Resource 获取 资源文件:
Resource resource = new ClassPathResource("application.xml");
InputStream in = resource.getInputStream();
step2:

在资源实现加载之前,调用了 super(parentBeanFactory) -- /**Ignore the given dependency interface for autowiring.(忽略接口的自动装配功能)*/
调用XmlBeanDefinitionReader 的 loadBeanDefinitions()方法进行加载资源:
(1) 对Resource资源进行编码
(2) 通过SAX读取XML文件来创建InputSource对象
(3) 核心处理

可以很直观的看出来是这个function是在解析xml文件从而获得对应的Document对象。

在doLoadDocument方法里面还存一个方法getValidationModeForResource()用来读取xml的验证模式。(和我关心的没什么关系,暂时不看了~)
转换成document也是最常用的方法:

step3 : 我们已经step by step 的看到了如何将xml文件转换成Document的,现在就要分析是如何提取和注册bean的。
/**Register the bean definitions contained in the given DOM document*/

参数doc是doLoadBeanDefinitions()方法传进来的 loadDocument 加载过来的。这边就很好的体现出了面向对象的单一全责原则,将逻辑处理委托給单一的类去处理。
在这边单一逻辑处理类是: BeanDefinitionDocumentReader
核心方法: documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

开始解析:

在Spring的xml配置中有两种方式来声明bean:
一种是默认的:
还有一种是自定义的: < tx : annotation-driven / >

通过xml配置文件的默认配置空间来判断:http://www.springframework.org/schema/beans
对于默认标签的解析:

对Bean 配置的解析:

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 返回BeanDefinitionHolder


这边代码大致看下来:
- 提取元素中的id和name属性
- 进一步解析将其他属性封装到 BeanDefinition 的实现类中
- 如果没有指定beanName 变使用默认规则生成beanName
- 封装类BeanDefinitionHolder
可以先了解一下 BeanDefinition 这个类的作用。
BeanDefinition是一个接口,对应着配置文件中里面的所有配置,在Spring中存在着三个实现类:

在配置文件中,可以定义父和子,父是用RootDefinition来表示,子是用ChildBeanDefinition来表示。
Spring 通过BeanDefiniton将配置文件中的配置信息转换为容器内部表示,并且将这些BeanDefinition注册到BeanDefinitonRegistry中。
Spring容器的BeanDefinitonRegistry就像是Spring配置信息的内存数据库,主要是以map的形式保存的。
因此解析属性首先要创建用于承载属性的实例:

然后就是各种对属性的解析的具体方法:

Spring源码剖析4:懒加载的单例Bean获取过程分析的更多相关文章
- 【Spring源码分析】非懒加载的单例Bean初始化过程(上篇)
代码入口 上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了f ...
- 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)
doCreateBean方法 上文[Spring源码分析]非懒加载的单例Bean初始化过程(上篇),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下 ...
- 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作
前言 之前两篇文章[Spring源码分析]非懒加载的单例Bean初始化过程(上篇)和[Spring源码分析]非懒加载的单例Bean初始化过程(下篇)比较详细地分析了非懒加载的单例Bean的初始化过程, ...
- Spring源码分析:非懒加载的单例Bean初始化前后的一些操作
之前两篇文章Spring源码分析:非懒加载的单例Bean初始化过程(上)和Spring源码分析:非懒加载的单例Bean初始化过程(下)比较详细地分析了非懒加载的单例Bean的初始化过程,整个流程始于A ...
- Spring源码分析:非懒加载的单例Bean初始化过程(下)
上文Spring源码分析:非懒加载的单例Bean初始化过程(上),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下AbstractAutowireC ...
- Spring源码分析:非懒加载的单例Bean初始化过程(上)
上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了finish ...
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...
- 05 flask源码剖析之配置加载
05 Flask源码之:配置加载 目录 05 Flask源码之:配置加载 1.加载配置文件 2.app.config源码分析 3.from_object源码分析 4. 总结 1.加载配置文件 from ...
- webpack4.X源码解析之懒加载
本文针对Webpack懒加载构建和加载的原理,对构建后的源码进行分析. 一.准备工作 首先,init之后创建一个简单的webpack基本的配置,在src目录下创建两个js文件(一个主入口文件和一个非主 ...
随机推荐
- RzPageControl(pagecontrol)
实现多标签的动态添加,切换,关闭 使用RzPageControl来实现多标签页使用菜单来打开标签页,通过标签页的caption来判断将标签页是否已经被打开过了.1.创建标签页,并判断是否是已经打开过的 ...
- 探索Redis设计与实现7:Redis内部数据结构详解——intset
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- 创建线程方法&守护线程
创建线程方法1. class mythread extends Thread{ 重写run方法 } mythread m=new mythread () 启动:m.start() 创建线程方法2. c ...
- dubbo超时原理以及解决方案
dubbo超时原理以及解决方案 本篇主要记录dubbo中关于超时的常见问题,实现原理,解决的问题 超时问题 为了检查对dubbo超时的理解,尝试回答如下几个问题,如果回答不上来或者不确定那么说明此处需 ...
- 导出数据库数据到Excel表
后台需要将用户信息数据导入到Excel表中提供给相关人员: 首先查询数据就不多说了: 导入Excel表直接亮代码(采用的是jxl的jar包提供的方法): public static File Impo ...
- TreeMap源码解析笔记
常见的数据结构有数组.链表,还有一种结构也很常见,那就是树.前面介绍的集合类有基于数组的ArrayList,有基于链表的LinkedList,还有链表和数组结合的HashMap,今天介绍基于树的Tre ...
- 归并排序(Merge_Sort)
基本思想 建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 算法原理 归并操作指的是将两个已经排序的序列合并成一个序列的操作,归并 ...
- sudo: unable to resolve host 枝桠
Ubuntu环境, 主机名字叫枝桠(机器的hostname), 每次执行sudo 就出现这个警告讯息: 虽然sudo 还是可以正常执行, 所以就直接从/etc/hosts 设定, 让枝桠(hostna ...
- python之数据序列转换并同时计算数据
问题 你需要在数据序列上执行聚集函数(比如 sum() , min() , max() ), 但是首先你需要先转换或者过滤数据 解决方案 一个非常优雅的方式去结合数据计算与转换就是使用一个生成器表达式 ...
- ionic ios上状态栏和app重叠解决方案
干货文章 ·2018-03-22 01:33:01 官方issues: https://github.com/ionic-team/ionic/issues/13294 解决办法: 1.在 confi ...