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

IoC容器的初始化过程概要

IoC容器的初始化包括三个过程:

  • 第一个过程是 Resource定位 过程。这个Resource定位指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一接口。比如.在文件系统中的Bean定义信息可以使用FileSystemResource来进行抽象。在类路径中的Bean定义信息可以使用ClassPathResource来进行抽象等等。这个定位过程类似于容器寻找数据的过程,就像用水捅装水先要把水找到一样。

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

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

几个常用的ApplicationContext

1. FileSystemXmlApplicationContext

FileSystemXmlApplicationContext的继承体系:

由继承关系可知,FileSystemXmlApplicationContext通过继承AbstractApplicationContext具备了DefaultResourceLoader读取Resource定义的BeanDefinition的能力。因为AbstractApplicationContext的基类是DefaultResourceLoader

看看其完整继承体系:

2. ClassPathXmlApplicationContext

ClassPathXmlApplicationContext的继承体系:

由继承关系可知,ClassPathXmlApplicationContext通过继承AbstractApplicationContext具备了DefaultResourceLoader读取Resource定义的BeanDefinition的能力。因为AbstractApplicationContext的基类是DefaultResourceLoader。和上面的FileSystemXmlApplicationContext如出一辙。

看看其完整继承体系:

3. AnnotationConfigApplicationContext

AnnotationConfigApplicationContext的继承体系:

可以看到,AnnotationConfigApplicationContext,也是通过DefaultResourceLoader读取Resource

看看其完整继承体系:

详细分析IoC初始化过程

以常用的ClassPathXmlApplicationContext为例:

1、 新建resources/META-INF/spring/context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.source.IoC.domain.User"><property name="name" value="张三"/></bean></beans>

2、 新建User

public class User {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

3、

public static void main(String args[]) {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();applicationContext.setConfigLocation("classpath:/META-INF/spring/context.xml");applicationContext.refresh();User user = applicationContext.getBean("user", User.class);System.out.printf("user.getName() = %s \n", user.getName());}

运行main方法,整个运行过程如下:

所以这里主要要来看一看AbstractApplicationContext中的refresh() 这个函数:

 public void refresh() throws BeansException, IllegalStateException {Object var1 = this.startupShutdownMonitor;synchronized(this.startupShutdownMonitor) {this.prepareRefresh();//这里是在子类中启动refreshBeanFactory()定位并载入ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//prepare the bean factory for use in this contextthis.prepareBeanFactory(beanFactory);try {//设置BeanFactory的后置处理this.postProcessBeanFactory(beanFactory);//调用BeanFactory的后处理器,这些后处理器是在Bean定义中想容器注册的this.invokeBeanFactoryPostProcessors(beanFactory);//注册Bean后处理器,在Bean创建过程中调用this.registerBeanPostProcessors(beanFactory);//对上下文中的消息源进行初始化this.initMessageSource();//初始化上下文中的事件机制this.initApplicationEventMulticaster();//初始化其他的特殊Beanthis.onRefresh();//检查监听Bean并且将这些Bean向容器注册this.registerListeners();//实例化所有的(non-lazy-init)单件this.finishBeanFactoryInitialization(beanFactory);//发布容器事件,结束Refresh过程this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}//为防止Bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件Beanthis.destroyBeans();//重置'active'标志this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

这个obtainFreshBeanFactory很关键,这里面有 IoC的Resource定位和载入

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {//资源定位和载入,是一个抽象方法,在子类AbstractRefreshableApplicationContext中实现的方法this.refreshBeanFactory();//getBeanFactory是一个抽象方法,在子类AbstractRefreshableApplicationContext中实现的方法ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();if (this.logger.isDebugEnabled()) {this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);}return beanFactory;}

看看refreshBeanFactory()源码如下:

   protected final void refreshBeanFactory() throws BeansException {//这里判断,如果建立了BeanFactory,则销毁并关闭该BeanFactoryif (this.hasBeanFactory()) {this.destroyBeans();this.closeBeanFactory();}try {//这里的创建并设置持有的DefaultListableBeanFactor的地方DefaultListableBeanFactory beanFactory = this.createBeanFactory();beanFactory.setSerializationId(this.getId());this.customizeBeanFactory(beanFactory);//载入Bean ,抽象方法,委托子类AbstractXmlApplicationContext实现this.loadBeanDefinitions(beanFactory);Object var2 = this.beanFactoryMonitor;synchronized(this.beanFactoryMonitor) {this.beanFactory = beanFactory;}} catch (IOException var5) {throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);}}

看看子类AbstractXmlApplicationContext中实现的loadBeanDefinitions

 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {Resource[] configResources = this.getConfigResources(); //只可能为nullif (configResources != null) { //不会走这一条路 参数类型Resource...reader.loadBeanDefinitions(configResources);}String[] configLocations = this.getConfigLocations();if (configLocations != null) { // 参数类型String... reader.loadBeanDefinitions(configLocations);}}@Nullableprotected Resource[] getConfigResources() {return null;}

继续往下看AbstractBeanDefinitionReader流操作类的loadBeanDefinitions,这里的流操作来实现IoC的载入

     public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {Assert.notNull(locations, "Location array must not be null");int counter = 0;String[] var3 = locations;int var4 = locations.length;for(int var5 = 0; var5 < var4; ++var5) {String location = var3[var5];counter += this.loadBeanDefinitions(location); //调用下面的函数}return counter;}public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {return this.loadBeanDefinitions(location, (Set)null); //调用下面的函数}public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {ResourceLoader resourceLoader = this.getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");} else {int loadCount;if (!(resourceLoader instanceof ResourcePatternResolver)) {Resource resource = resourceLoader.getResource(location);loadCount = this.loadBeanDefinitions((Resource)resource);if (actualResources != null) {actualResources.add(resource);}if (this.logger.isDebugEnabled()) {this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");}return loadCount;} else {try {Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);loadCount = this.loadBeanDefinitions(resources);if (actualResources != null) {Resource[] var6 = resources;int var7 = resources.length;for(int var8 = 0; var8 < var7; ++var8) {Resource resource = var6[var8];actualResources.add(resource);}}if (this.logger.isDebugEnabled()) {this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");}return loadCount;} catch (IOException var10) {throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);}}}}

loadBeanDefinitions会调用DefaultResourceLoader中的getResource

public Resource getResource(String location) {Assert.notNull(location, "Location must not be null");Iterator var2 = this.protocolResolvers.iterator();Resource resource;do {if (!var2.hasNext()) {if (location.startsWith("/")) {return this.getResourceByPath(location);}if (location.startsWith("classpath:")) {return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());}try {URL url = new URL(location);return (Resource)(ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));} catch (MalformedURLException var5) {return this.getResourceByPath(location);}}ProtocolResolver protocolResolver = (ProtocolResolver)var2.next();resource = protocolResolver.resolve(location, this);} while(resource == null);return resource;}

可以看到,getResource又调用了子类实现的getResourceByPath方法或是子类传递过来的字符串,实现 Resource定位

整个过程就说得通了。总结起来就是,Resource资源通过最外层的实现类传进来的字符串或者直接调用getResourceByPath方法,来获取bean资源路径,然后通过AbstractBeanDefinitionReader流操作实现载入,最后通过AbstractApplicationContextregisterListeners 进行注册。这就是IoC容器的初始化过程。

其他容器的初始化过程,由上面的继承关系对比,就可以知道是差不多的,这里就不一个一个分析了。

IOC原理之IoC容器的初始化过程相关推荐

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

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

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

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

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

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

  4. Spring IoC(二)IoC容器的初始化过程

    (一)IoC 容器初始化过程概述 1.1简要概述初始化过程 IoC 容器的初始化过程是通过refresh() 方法来启动的,这个方法标识着IoC 容器正式启动.具体来说,这个启动过程包括:BeanDe ...

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

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

  6. Spring容器的初始化过程

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

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

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

  8. java ioc 原理_Spring IoC原理

    Spring IoC(DI)是Spring框架的核心,所有对象的生命周期都是由它们来管理.对于弄懂Spring IOC是相当关键,往往我们第一次接触Spring IOC大家都是一头雾水.当然我们这篇文 ...

  9. Java Spring实现原理研究之Servlet initialization初始化过程

    Created by Wang, Jerry, last modified on Jul 25, 2016

最新文章

  1. 路由器虚拟服务器功能(广域网服务端口和局域网服务端口的映射关系)
  2. 赛灵思PLL重配置一PLL配置介绍___S6器件族
  3. Altium Designer中将FPGA引脚定义导出成文件
  4. elasticsearch 5.6.x单机环境构建(集成head插件和IK中文分词)
  5. C#实现乞丐版IOC容器
  6. 吴恩达神经网络1-2-2_图神经网络进行药物发现-第1部分
  7. HTML+CSS+JS实现 ❤️卡通湖面上日出动画特效❤️
  8. 极简风格的响应式简历模板
  9. Linux LAMP架构搭建
  10. Atitit 编程语言的类型系统 目录 1.2. 动态类型语言(Dynamically Typed Language): 1 1.3. 静态类型语言(Statically Typed Languag
  11. FGSM对抗样本trick汇总
  12. Halcon 3D 计算3D模型的3D表面法线
  13. 三菱PLC排故障的方法
  14. 非接触物体尺寸形态测量(G 题)
  15. 混合模式程序集是针对“v1.1.4322”版的执行时生成的,在没有配置其它信息的情况下,无法在 4.0 执行时中载入该程序集。...
  16. 机器学习训练营--快来一起挖掘幸福感吧
  17. 【学习笔记】C++ GUI Qt4 第六章 6.4 滚动区域 和 6.5 停靠窗口和工具栏
  18. 【Pygame实战】妈耶~这款经典的《俄罗斯方块儿》竟这么厉害......
  19. 7 张简单图片帮你弄懂企业级架构
  20. C2C、B2B、B2C解释(转)

热门文章

  1. 计算机中丢失mwusb,icbc_mwusbkey.dll
  2. 苹果cmsV10 短视多功能主题5.1版本
  3. Python+Behave+Allure Web UI自动化测试
  4. Self Attention 详解
  5. AI魔法秀:D-ID助你打造视频虚拟数字人
  6. 最新信息安全毕设选题题目推荐
  7. linux cpio 备份系统,linux备份命令-cpio
  8. FL Studio中文版21最新免费音乐编曲软件制作工具
  9. 第十四周项目二成绩姓名排名
  10. 渗透靶机(CMS漏洞)