IOC原理之IoC容器的初始化过程
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
流操作实现载入,最后通过AbstractApplicationContext
的registerListeners
进行注册。这就是IoC容器的初始化过程。
其他容器的初始化过程,由上面的继承关系对比,就可以知道是差不多的,这里就不一个一个分析了。
IOC原理之IoC容器的初始化过程相关推荐
- [Spring 深度解析]第7章 IoC容器的初始化过程
7. IoC容器的初始化过程 简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动.具体来说,这个启动包括BeanDefinition的Re ...
- SpringBoot启动流程分析(四):IoC容器的初始化过程
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- 《Spring技术内幕》——2.3节IoC容器的初始化过程
2.3 IoC容器的初始化过程 简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动.具体来说,这个启动包括BeanDefinition的Res ...
- Spring IoC(二)IoC容器的初始化过程
(一)IoC 容器初始化过程概述 1.1简要概述初始化过程 IoC 容器的初始化过程是通过refresh() 方法来启动的,这个方法标识着IoC 容器正式启动.具体来说,这个启动过程包括:BeanDe ...
- Spring IOC学习心得之IOC容器的初始化过程
注:本文大多数内容都是摘自<Spring技术内幕>这本书 简单来说,Ioc容器的初始化过程是在refresh()方法中启动的,包括BeanDefinition的Resource定位,载入和 ...
- Spring容器的初始化过程
1.Spring 容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配号Bean之间的依 ...
- Spring IoC容器的初始化过程
转载自:http://blog.csdn.net/u010723709/article/details/47046211 原题是:2 IOC容器初始化过程 作者:@小小旭GISer ========= ...
- java ioc 原理_Spring IoC原理
Spring IoC(DI)是Spring框架的核心,所有对象的生命周期都是由它们来管理.对于弄懂Spring IOC是相当关键,往往我们第一次接触Spring IOC大家都是一头雾水.当然我们这篇文 ...
- Java Spring实现原理研究之Servlet initialization初始化过程
Created by Wang, Jerry, last modified on Jul 25, 2016
最新文章
- 路由器虚拟服务器功能(广域网服务端口和局域网服务端口的映射关系)
- 赛灵思PLL重配置一PLL配置介绍___S6器件族
- Altium Designer中将FPGA引脚定义导出成文件
- elasticsearch 5.6.x单机环境构建(集成head插件和IK中文分词)
- C#实现乞丐版IOC容器
- 吴恩达神经网络1-2-2_图神经网络进行药物发现-第1部分
- HTML+CSS+JS实现 ❤️卡通湖面上日出动画特效❤️
- 极简风格的响应式简历模板
- Linux LAMP架构搭建
- Atitit 编程语言的类型系统 目录 1.2. 动态类型语言(Dynamically Typed Language):	1 1.3. 静态类型语言(Statically Typed Languag
- FGSM对抗样本trick汇总
- Halcon 3D 计算3D模型的3D表面法线
- 三菱PLC排故障的方法
- 非接触物体尺寸形态测量(G 题)
- 混合模式程序集是针对“v1.1.4322”版的执行时生成的,在没有配置其它信息的情况下,无法在 4.0 执行时中载入该程序集。...
- 机器学习训练营--快来一起挖掘幸福感吧
- 【学习笔记】C++ GUI Qt4 第六章 6.4 滚动区域 和 6.5 停靠窗口和工具栏
- 【Pygame实战】妈耶~这款经典的《俄罗斯方块儿》竟这么厉害......
- 7 张简单图片帮你弄懂企业级架构
- C2C、B2B、B2C解释(转)