(一)IoC 容器初始化过程概述

1.1简要概述初始化过程

IoC 容器的初始化过程是通过refresh() 方法来启动的,这个方法标识着IoC 容器正式启动。具体来说,这个启动过程包括:BeanDefinition 的Resource 定位、载入和注册三个基本过程。

Spring 把这三个过程分开,并使用不同的模块来完成,通过这样的设计方式,可以让用户更加灵活的对这三个过程进行裁剪或扩展,从而方便自己定义IoC 容器的初始化过程。

第一个过程是Resource 的定位过程。这个Resource 的定位指的是BeanDefinition 的资源定位,它由ResourceLoader 通过统一的Resource 接口来完成。对于BeanDefinition 的存在形式,可以是文件系统中的,通过FileSystemResource 来进行抽象;类路径中定义的Bean 信息可以通过ClassPathResource 来进行抽象。等等。这个过程可以理解为IoC 容器寻找数据的过程。

第二个过程是BeanDefinition 的载入。这个载入过程是把用户定义好的Bean 定义成IoC 容器内部的数据结构,而这个容器内部数据结构就是BeanDefinition。具体来说,这个BeanDefinition 实际上就是POJO 对象在IoC 容器中的抽象,通过这个BeanDefinition 定义的数据结构,使IoC 容器能够方便地管理Bean。

第三个过程是向IoC 容器中注册这些BeanDefinition 的过程。这个过程是通过BeanDefinitionRegistry 接口的实现来完成的。这个注册过程把载入过程中解析得到的BeanDefinition 向IoC 容器进行注册。在IoC 容器内部将BeanDefinition 注入到一个HashMap 中去,IoC 容器就是通过这个HashMap 来持有这些Bean 数据的。

这里谈的IoC 容器的初始化过程,并不包含Bean 依赖注入的实现。在Spring IoC 的设计中,Bean 定义的载入和依赖注入是两个独立的过程。依赖注入一般发生在第一个通过getBean() 向容器中获取Bean 的时候。但是也并不全是这样,比如我们对某个Bean 设置了lazyinit 属性,那么Bean 的依赖注入在其初始化的过程中就已经完成了。

(二)IoC 容器具体初始化过程解析

2.1BeanDefinition 的Resource 定位

ApplicationContext 是一个接口,其实现类主要有:FileSystemXmlApplicationContext、
ClassPathXmlApplicationContext 和XmlWebApplicationContext 等。从这些类的名字就可以分析的出其加载文件的位置。FileSystemXmlApplicationContext 可以从文件系统中载入Resource、ClassPathXmlApplicationContext 可以从类路径下载入Resource、XmlWebApplicationContext 可以从Web 容器中载入Resource。

这里以FileSystemXmlApplicationContext 为例,来分析ApplicationContext 的实现是如何完成Resource 定位的,下面是这个类对应的继承体系。

下面是更为详细的继承体系。

从上图中可以看出FileSystemXmlApplicationContext 已经通过继承AbstractApplicationContext 具备了ResourceLoader 的功能,因为AbstractApplicationContext 继承自DefaultResourceLoader。下面是其源代码:

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {public FileSystemXmlApplicationContext() {}public FileSystemXmlApplicationContext(ApplicationContext parent) {super(parent);}/*** * @param configLocation 表示BeanDefinition 所在的文件路径* @throws BeansException*/public FileSystemXmlApplicationContext(String configLocation) throws BeansException {this(new String[] {configLocation}, true, null);}/*** * @param configLocations 表示BeanDefinition 文件数组所在的路径* @throws BeansException*/public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {this(configLocations, true, null);}/*** * @param configLocations 可以包含多个BeanDefinition 的文件路径* @param parent 指定自己的IoC 双亲容器* @throws BeansException*/public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {this(configLocations, true, parent);}/*** * @param configLocations 文件数组* @param refresh 是否自动刷新上下文* @throws BeansException*/public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {this(configLocations, refresh, null);}public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();}}/*** 文件系统中Resource 的实现,通过一个FileSystemResource 来得到一个在文件系统中定位的BeanDefinition* @param path 文件路径* @return*/@Overrideprotected Resource getResourceByPath(String path) {if (path != null && path.startsWith("/")) {path = path.substring(1);}return new FileSystemResource(path);}}

对BeanDefinition 资源定位的过程,最初是由refresh() 方法触发的,refresh() 方法的调用是在
FileSystemXmlApplicationContext 的构造函数中启动的。getResourceByPath() 方法的调用过程主要如下:

从上面的源代码中可以看出,只要是以XML 文件方式存在的BeanDefinition 都能够得到有效的处理。上面的源代码中并没有涉及到BeanDefinition 的信息读入,那么FileSystemXmlApplicationContext 是怎么完成信息的读入的呢?
上面已经提到过BeanDefinition 资源的定位、载入和注册过程都是分开进行的。关于这个读入器的配置,可以在FileSystemXmlApplicationContext 的基类AbstractRefreshableApplicationContext 中查看。

这里主要看AbstractRefreshableApplicationContext 中的refreshBeanFactory() 方法的实现,
这个方法被FileSystemXmlApplicationContext 构造函数中的refresh() 方法所调用。在refreshBeanFactory()这个方法中,通过createBeanFactory() 创建一个IoC 容器供AppliCationContext 使用。这个IoC 容器就是上一篇博文中提到的DefaultListableBeanFactory。同时,还启动了loadBeanDefinitions() 来载入BeanDefinition。下面是refreshBeanFactory() 的方法的源码:

 @Overrideprotected final void refreshBeanFactory() throws BeansException {// 如果已经建立了BeanFactory,则销毁并关闭if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 通过createBeanFactory() 方法获得一个创建的IoC 容器// 创建的是DefaultListableBeanFactory 容器DefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);// 载入BeanDefinitionloadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}

在BeanDefinition 定位完成的基础上,就可以通过返回的Resource 对象来进行BeanDefinition 的载入了。在完成定位过程后,为BeanDefinition 的载入创造了I/O 操作的条件,但是具体的数据还没有开始读入。

2.2BeanDefinition 的载入和解析

先发出来,慢慢更!

Spring IoC(二)IoC容器的初始化过程相关推荐

  1. [Spring 深度解析]第7章 IoC容器的初始化过程

    7. IoC容器的初始化过程 ​ 简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动.具体来说,这个启动包括BeanDefinition的Re ...

  2. 《Spring技术内幕》——2.3节IoC容器的初始化过程

    2.3 IoC容器的初始化过程 简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动.具体来说,这个启动包括BeanDefinition的Res ...

  3. Spring IOC学习心得之IOC容器的初始化过程

    注:本文大多数内容都是摘自<Spring技术内幕>这本书 简单来说,Ioc容器的初始化过程是在refresh()方法中启动的,包括BeanDefinition的Resource定位,载入和 ...

  4. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  5. IOC原理之IoC容器的初始化过程

    IoC容器的初始化过程包括Resource定位.BeanDefinition的载入以及向IoC容器注册这些BeanDefinition三个阶段. IoC容器的初始化过程概要 IoC容器的初始化包括三个 ...

  6. Spring容器的初始化过程

    1.Spring 容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配号Bean之间的依 ...

  7. Spring MVC 原理探秘 - 容器的创建过程

    1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的.Spring MVC 可对外提供服务时,说明其已经处于了就绪状态.再次之前,Spring MVC 需要进行 ...

  8. Spring IoC容器的初始化过程

    转载自:http://blog.csdn.net/u010723709/article/details/47046211 原题是:2 IOC容器初始化过程 作者:@小小旭GISer ========= ...

  9. Spring源码-AnnotationConfigApplicationContext容器的创建过程

    Spring提供了多种IOC容器用来管理bean,其中最常见的就是AnnotationConfigApplicationContext AnnotationConfigApplicationConte ...

最新文章

  1. 【Spark】Spark基础练习题(一)
  2. 谷歌这波大动作,暴露了什么信号?
  3. 夏天写代码真难!16G 内存根本不够用! | 每日趣闻
  4. 【Oracle RAC+DG实验】Oracle RAC+ASM+DataGuard配置实验记录+常见问题
  5. Java 拖拽文件到文本框
  6. 数据分析之pandas常见的数据处理(四)
  7. 基于Android的ELF PLT/GOT符号重定向过程及ELF Hook实现
  8. 前端学习(2499):Property or method “name“ is not defined on the instance but referenced during render. Ma
  9. shell脚本判断文件类型
  10. linux重定向到程序,技术|Linux I/O 重定向基础
  11. quartz定时程序无故停止并且没有错误
  12. JavaSE--异常信息打印
  13. 明小子3.5检测网站应用
  14. 富士通Fujitsu DPK8510E 打印机驱动
  15. 推荐这几个数据大屏可视化开发工具
  16. 【必看文件含发帖规范】2020年黑马程序员社区总版规发布!
  17. Syzmlw 蜗居在线播放
  18. android 恢复出厂设置流程分析,Android恢复出厂设置流程分析
  19. 奥塔哥大学计算机科学怎样,2019QS世界大学学科排名出炉,新西兰最强专业看过来!...
  20. 最详细windows xp下安装mac的教程(转自远景论坛69nc)

热门文章

  1. Spring Boot-@Value获取值和@ConfigurationProperties获取值的比较
  2. 牛客题霸 NC4 判断链表中是否有环
  3. Go——Artifactory的AQL查询以及json解析解决方案
  4. 软件测试——StringFunction测试
  5. TensorFlow学习笔记之三(神经网络的优化)
  6. Mysql慢查询深入剖析_《深入精通Mysql(六)》系列之如何通过慢查询日志进行SQL分析和优化...
  7. arm linux 核心板 制作,Linux下制作给ARM开发板使用的文件系统
  8. 【两数之和】算法优化笔记
  9. C++ map 中的reverse_iterator
  10. 北邮OJ 85. Three Points On A Line