大致的加载过程:

spring ioc容器的加载,大体上经过以下几个过程: 资源文件定位、解析、注册、实例化

1.资源文件定位:主要发生在ApplicationContext中,由于applicationContext继承于ResourceLoader,所以调用getResource()方法,将外部的资源解析成Resource类

2.解析:主要发生在BeanDefinitionReader中完成,最常用的类是XMLBeanDefiniationReader,

ac利用loadBeanDefininiation()方法,负责读取Resource;将Resource的解析交给XMLbeanDefiniationReader去处理,

将XML文档解析成w3c的Document文档,BeanDefinitionDocumentReader进一步解析,BeanDefinitionDocumentReader将Document,交给BeanDefiniationParserDetegate去处理(装饰),如果是标准的NameSpace文档(import、alias、bean、beans),在内部解析,如果不是标准的文档,会委托合适的NameSpaceHander去处理进行解析,将结果封装到BeanDefiniationHolder,最后调用一个工具类来完成对BeanDefinintion的注册

3.注册

Bean的注册是在BeanFactory中完成的,BeanFactory最常用的一个实现类是DefaultListableBeanFactory,它实现了BeanDefinitionRegistry接口,调用了registerBeanDefinition()方法,从而对BeanDefinition进行注册.

所谓的注册就是将BeanDefinition的name和实例保存到一个CurrentHashMap中,最常用的实现DefaultListableBeanFactory,其中的字段就是beanDefinitionMap,是一个ConcurrentHashMap

4.实例化:

注册也完成之后,在BeanFactory的getBean()方法之中,会完成初始化

容器初始化的核心

Refresh()方法

            //1.刷新前的预处理
// Prepare this context for refreshing.
prepareRefresh();
//2.获取beanfactory
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//3.beanFactory的预准备工作
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
//4.为BeanFactory准备工作完成后,添加一些的后置处理器(用户自定义)
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
//5.执行beanFacotry的后置处理器
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
//6.注册Bean的后置处理器
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
//7.初始化消息资源管理(主要用于国际化、消息绑定、消息解析)
// Initialize message source for this context.
initMessageSource();
//8.初始化事件的派发器
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
//9.重新刷新容器,留给子类重写该方法,进行自定义
// Initialize other special beans in specific context subclasses.
onRefresh();
//10.将容器中的ApplicationListener注册进来
// Check for listener beans and register them.
registerListeners();
//11.初始化所有的非懒加载的Bean实例
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
//12.完成BeanFactory的初始化创建工作
// Last step: publish corresponding event.
finishRefresh();
//IOC容器创建完成

1.prepareRerfresh()

(1), initPropertySources初始化一些属性设置

(2),getEnvironment().validateRequiredProperties();校验属性和环境的相关设置

(3), this.earlyApplicationEvents = new LinkedHashSet<>();保存容器中的一些早期事件

2.obtainFreshBeanFactory()

(1)refreshBeanFactory();创建BeanFactory对象

    1.如果有BeanFactory,就清空

2.createBeanFactory()创建DefaultListableBeanFactory对象

3.beanFactory.setSerializationId(getId());设置标识符

4.customizeBeanFactory()允许用户自定义一些设置

5.loadBeanDefinitions()解析XML文件并注册成BeanDefinition对象

<1>创建XMLBeanDefinitionReader对象,new XmlBeanDefinitionReader(beanFactory);

beanFactory其实是BeanDefinitionRegistry对象,因为DefaultListableBeanFactory实现了

BeanDefinitionRegistry接口                            

<2>设置并初始化XMLBeanDefinitionReader对象

<3>loadBeanDefinition(beanDefinitionReader)解析XML文件并注册成BeanDefinition对象

的真正方法

其内部: XmlBeanDefinitionReader无法直接解析配置文件,所以利用了ResourceReader

将Location配置文件封装成Resource,然后调用重载的方法,先将Resource转换成  

InputStream在解析成w3c的Doucment对象,最后调用RegisterBeanDefinitions()

RegisterBeanDefinitions()内部实现:创建一个BeanDefinitionDocumentReader对象 起到路由的作用

1.该对象会委托BeanDefinitionParserDelegate()进行真正的解析doc

调用delegate.parseBeanDefinitionElement(ele),如果是标准的NameSpace文档

(import、alias、bean、beans),在内部解析,如果不是标准的文档,会委托合适的

                          NameSpaceHander去处理进行解析,将结果封装到BeanDefiniationHolder

2.调用Delegate对BeanDefinition进行装饰

  3.最后调用工具类方法,进行注册,其实调用的是DefaultListableBeanFactory中的    

                        registerBeanDefinition(),该方法主要是beanName放到队列(beanDefinitionNames)                         里,然后把BeanDefinition放到beanDefinitionMap.put(beanName, beanDefinition) <concurrentHashMap>

(2)getBeanFactory() 获取BeanFactory对象,并返回ConfigurableListableBeanFactory对象

3.prepareBeanFactory(beanFactory)

4.postProcessBeanFactory(beanFactory)

5.invokeBeanFactoryPostProcessors( beanFactory)

执行BeanFactoryPostProcessor的方法;

里有2个接口BeanDefinitionRegistryPostProcessor(BeanFactoryPostProcessors的子类)、BeanFactoryPostProcessors都将会执行它们的后置处理器的方法

1.先执行BeanDefinitionRegistryPostProcessor的方法,(beanDefinition将要被加载在beanfactory中但是还没有实例化,作用是用于自己添加beanDefinition)

     1)、获取所有的BeanDefinitionRegistryPostProcessor;
2)、看先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、
postProcessor.postProcessBeanDefinitionRegistry(registry)
3)、在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor;
postProcessor.postProcessBeanDefinitionRegistry(registry)
4)、最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors;
postProcessor.postProcessBeanDefinitionRegistry(registry)

2.否则的话,BeanFactoryPostProcessor的方法(beanfactory标准初始化之后,来定制beanfactory的内容,所有的beanDefinition已经保存到了beanfactory中但是还没有实例化)

1)、获取所有的BeanFactoryPostProcessor
2)、看先执行实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor、
postProcessor.postProcessBeanFactory()
3)、在执行实现了Ordered顺序接口的BeanFactoryPostProcessor;
postProcessor.postProcessBeanFactory()
4)、最后执行没有实现任何优先级或者是顺序接口的BeanFactoryPostProcessor;
postProcessor.postProcessBeanFactory()

6.RegistryBeanPostProcessor

不同接口类型的BeanPostProcessor,在Bean创建执行前后是不一样的

BeanPostProcessor、 DestructionAwareBeanPostProcessor、 InstantiationAwareBeanPostProcessor、 SmartInstantiationAwareBeanPostProcessor、 MergedBeanDefinitionPostProcessor【internalPostProcessors】、

(1)先获取所有的BeanPostProcessor,这些后置处理器可以通过PriorityOrdered、Ordered接口来执行优先级

(2)先将实现了PriorityOrdered优先级接口的BeanPostProcessor注册到BeanFactory

把每一个BeanPostProcessor注册到BeanFactory中

beanFactory.addBeanPostProcessor(postProcessor);

(3)在注册实现了Ordered接口的BeanPostProcessor

(4)最后注册没有实现任何优先级接口的

(5)、最后注册一个ApplicationContextListenerDetector的后置处理器,用于在Bean创建完成后检查是否为ApplicationContextListener,是的话,就会调用ApplicationContext.addApplicationListener((ApplicationListener<?>) bean)将其添加到容器中

7.InitMessageSource

1.获取BeanFactory

2.看容器中是否有id为messageSource的,类型是MessageSource的组件

如果没有就创建一个DelegatingMessageSource,然后把messageSource注入到容器,以后获取国际化的资源可以根据messageSource来获取

8.InitApplcationEventMulticaster

(基于事件派发的组件)

1.获取BeanFactory

2.看容器中是否有id为applicationEventMulticaster的组件

如果没有就创建一个SimpleApplicationEventMulticaster,然后把它注入到容器.

9.onRefresh();

子类重写这个方法,在容器刷新的时候可以自定义逻辑;

10.registerListeners()

1.从容器中获取所有的ApplicationListener

2.将每个监听器添加到事件派发器中; getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

11.finishBeanFactoryInitialization()

实际上调用的是DefaultListableBeanFactory的preInstantiateSingleton()方法

preInstantiateSingleton()

1.遍历BeanDefinitionMap

2.在遍历的时候,调用getMergedLocalBeanDefinition(beanName)将其转换成RootBeanDefinition

注意:普通的Bean在Spring加载Bean定义的时候,实例化出来的是GenericBeanDefinition,而Spring上下文包括实例化所有Bean用的AbstractBeanDefinition是RootBeanDefinition,这时候就使用getMergedLocalBeanDefinition方法做了一次转化,将非RootBeanDefinition转换为RootBeanDefinition以供后续操作

3.在遍历的时候,判断要实例化Bean1.非抽象2.是单例3.非延迟加载

4.在遍历的时候,先判断当前Bean是否为FactoryBean的实现(false,直接调用getBean(beanName))在判断是否为	 

     SmartFactoryBean的实现,假如Bean是SmartFactoryBean的实现并且为eagerInit(渴望加载),也会调用 

     getBean(beanName)立即实例化该Bean

	getBean(beanName)核心doGetBean()为父类AbstractBeanFactory类的doGetBean方法 

	doGetBean()方法

		1.先判断本地的单例缓存中是否缓存过该Bean,如果有缓存就直接从缓存中获取

		2.然后进行一些基本检验,比如检查depend-on属性,用来保证具有依赖关系的Bean先被加载

		3.调用createBean(beanName, mbd, args)用于创建单实例对象

		     1.resolveBeforeInstantiation();
创建bean实例前,让BeanPostProcessor先拦截,是否能返回代理对象;
也就是给beanPostProcessor一个返回bean的代理对象机会
内部是【InstantiationAwareBeanPostProcessor】这个拦截器(和AOP有关)
先触发:postProcessBeforeInstantiation(beanClass, beanName);
如果有返回值Object bean ,就不会创建bean了在调用 postProcessAfterInitialization(beanClass, beanName)并返回代理bean
[InstantiationAwareBeanPostProcessor]没有的代理的bean调用doCreateBean() 2.doCreateBean()
AbstractAutowireCapableBeanFactory 的doCreateBean()方法
<1>.创建Bean实例,并包装成BeanWrapper
createBeanInstance()方法
判断当前的Bean里面使用的是空参构造还是有参数构造,然后通过反射生成Bean的实 例。看到前面有一步makeAccessible,这意味着即使Bean的构造函数是private、 protected的,依然不影响Bean的构造。这里被实例化出来的Bean并不会直接返回, 而是会被包装为BeanWrapper
<2>.允许后置处理器对其进行修改Bean定义
applyMergedBeanDefinitionPostProcessors()
会调用MergedBeanDefinitionPostProcessor的 postProcessMergedBeanDefinition(mbd, beanType, beanName);
<3>.属性注入
populateBean()方法
1)、在赋值之前,拿到InstantiationAwareBeanPostProcessor后置处理器
调用postProcessAfterInstantiation();
2)、继续拿到InstantiationAwareBeanPostProcessor后置处理器; 调用postProcessPropertyValues(); 赋值操作
3)、applyPropertyValues() 真正为属性赋值的方法
首先进行深拷贝(指的是深度拷贝,遍历PropertyValue然后一个一个赋值到 一个新的List,是为了解析Values值中的所有引用),然后在调用 bw.setPropertyValues(new MutablePropertyValues(deepCopy)),遍历 deepcopy对象拿到对应的set方法并将方法的可见性设置为true,最后利用反 射的机制,对Bean通过反射调用set()方法
(1)拿到写方法并将方法的可见性设置为true (2)拿到Value值,对Bean通过反射调用写方法
<4>.初始化Bean
initializeBean()方法
1).执行Aware()方法,调用invokeMethodAware(beanName, bean)方法 ,执行 xxxAware接口的方法
实现BeanNameAware/BeanClassLoaderAware/BeanFactoryAware.... 才会进行 调用,aware主要是属性赋值后获取其中的信息并且自定义修改
2).执行后置处理器在初始化之前 applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
BeanPostProcessor.postProcessBeforeInitialization();  
3).执行初始化的方法invokeInitMethods(beanName, wrappedBean, mbd)            
<1>、是否是InitializingBean接口的实现;执行接口规定的初始化;  
<2>、尝试去拿init-method,假如有的话,通过反射,调用initMethod;  
因此,两种方法各有优劣:使用实现InitializingBean接口的方式效率更高一点,因为init-method方法是通过反射进行调用的(JVM无法优化在内存中的动态对象);从另外一个角度讲,使用init-method方法之后和Spring的耦合度会更低一点
4).执行后置处理器在初始化之后applyBeanPostProcessorsAfterInitialization BeanPostProcessor.postProcessAfterInitialization();
5).注册bean的销毁方法,在容器关闭之前会自动的进行调用  
registerDisposableBeanIfNecessary(beanName, bean, mbd);
要注册销毁方法,Bean需要至少满足以下三个条件之一:
(1)Bean是DisposableBean的实现类,此时执行DisposableBean的接口方法 destroy()
(2)Bean标签中有配置destroy-method属性,此时执行destroy-method配置指定的 方法
(3)当前Bean对应的BeanFactory中持有DestructionAwareBeanPostProcessor接口 的实现类,此时执行 DestructionAwareBeanPostProcessor的接口方法 postProcessBeforeDestruction
4.创建好Bean后,将其添加到容器中
5.非单例非原型调用
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);(了解)如果bean是 FactoryBean的实现类的话,调用getObject()方法获取真正的对象。
流程总结:

[

12.finishRefresh()

1)、initLifecycleProcessor();初始化和生命周期有关的后置处理器;LifecycleProcessor 默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new

                  DefaultLifecycleProcessor();然后到加入到容器中
写一个LifecycleProcessor的实现类,可以在BeanFactory刷新或者关闭的时候进行调用
void onRefresh();
void onClose();

2)、 getLifecycleProcessor().onRefresh();

	拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh();

3)、publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件;

发布事件流程:1.获取事件派发器

2.multicastEvent派发事件

3.获取到所有的ApplicaitonListener

4.判断是否需要已异步还是同步的方式进行执行listener的onApplicationEvent()方法

SpringIOC源码分析总结的更多相关文章

  1. springIOC源码分析(BeanFactroy)

    启动spring容器加载bean的方式有两种:最基本的容器BeanFactory和高级容器ApplicationContext.这篇文章介绍使用BeanFactory加载bean时的整个过程,当然,A ...

  2. 设计模式(十四)——模板模式(SpringIOC源码分析)

    1 豆浆制作问题 编写制作豆浆的程序,说明如下: 1) 制作豆浆的流程 选材--->添加配料--->浸泡--->放到豆浆机打碎 2) 通过添加不同的配料,可以制作出不同口味的豆浆 3 ...

  3. spring IOC源码分析(ApplicationContext)

    在上一篇文章中,我们以BeanFactory这条主线进行IOC的源码解析的,这里,将以ApplicationContext这条线进行分析.先看使用方法: @Test public void testA ...

  4. springmvc源码分析

    Spring MVC源码分析--初始化过程 标签: springmvcconstructioniocclass 2012-09-09 21:32 26578人阅读 评论(3) 收藏 举报 版权声明:本 ...

  5. Spring源码分析专题 —— IOC容器启动过程(上篇)

    声明 1.建议先阅读<Spring源码分析专题 -- 阅读指引> 2.强烈建议阅读过程中要参照调用过程图,每篇都有其对应的调用过程图 3.写文不易,转载请标明出处 前言 关于 IOC 容器 ...

  6. dubbo源码分析02:服务引用

    一.何时创建服务引用 引用官方文档的原话,如果将Dubbo托管在Spring-IOC容器下,Dubbo服务引用的时机有两个,第一个是在Spring容器调用ReferenceBean的afterProp ...

  7. Spring源码分析之-加载IOC容器

    本文接上一篇文章 SpringIOC 源码,控制反转前的处理(https://mp.weixin.qq.com/s/9RbVP2ZQVx9-vKngqndW1w) 继续进行下面的分析 首先贴出 Spr ...

  8. Spring源码分析之IOC的三种常见用法及源码实现(一)

    1.ioc核心功能bean的配置与获取api 有以下四种 (来自精通spring4.x的p175) 常用的是前三种 第一种方式 <?xml version="1.0" enc ...

  9. SpringIOC源码解析(下)

    注意,看完这篇文章需要很长很长很长时间... 本篇文章是SpringIOC源码解析(上)的续集,上一篇文章介绍了使用XML的方式启动Spring,然后追踪了BeanFactory容器的创建.配置文件的 ...

随机推荐

  1. Hibernate错误:Could not bind factory to JNDI

    使用hibernate时,将hibernate.cfg.xml中 <session-factory name="SessionFactory">的那么属性去掉即可.因为 ...

  2. 百度NLP一面

    C++ :     1.拷贝构造函数和重载=符分别在什么情况下被调用,实现有什么区别 2.虚函数的目的,虚函数和模板类的区别,如何找到虚函数 常规算法: 1. 如何输出一个集合的所有真子集,递归和非递 ...

  3. Uvalive 7037 The Problem Needs 3D Arrays(最大密度子图)

    题意:给一段子序列,定义密度:子序列中的逆序对数/子序列的长度 求这个序列的对大密度. 分析:将序列中的每个位置视作点,逆序对\(<i,j>\)之间表示点i与点j之间有一条无向边.所以就转 ...

  4. Visual studio插件 Reshaper--- 常用快捷键

    快速修复 alt+enter (alt+enter唤出快速修复面板,上下方向键进行选择,再次敲击enter键确定修改) 跳转到对象声明 ctl+鼠标左键 重构-重命名(ctl+r+r) esc键退出 ...

  5. Web前端页面的浏览器兼容性测试心得(二)搭建原汁原味的IE8测试环境

    如果你做的页面被老板或PM要求兼容IE8,你就值得同情了.IE8不支持HTML5,在2017年的前端界,开发者不涉及HTML5标准简直寸步难行.然而,有一个可怕的事实客观存在,那就是IE8是Win7系 ...

  6. context.Request方法总结

    Request.Params为获取的包含上述两种集合外,还包括当前运行环境变量,COOKIES等的集合.Request.QueryString["param"] getReques ...

  7. 【Python】闭包 & 匿名函数

    闭包 1.注意:返回的函数内部不要使用后续会发生变化的变量. def f(): gs = [] for k in range(1, 4): def g(i): return i + k gs.appe ...

  8. Kafka学习之(一)了解一下Kafka及关键概念和处理机制

    Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模小打的网站中所有动作流数据.优势 高吞吐量:非常普通的硬件Kafka也可以支持每秒100W的消息,即使在非常廉价的商用机器上也能做 ...

  9. Error: Flash Download failed - "Cortex-M0"

    今天在调试程序时.DEMO板下载几次后就提示Flash下载失败:                         Keil v4里面的设置都没有动过.不可能被修改.此时.使用新唐的ICP Progra ...

  10. java计算两个日期之间相隔的月份(向下取整)

    最近需求里面有个需要计算两个日期之间相隔的月份,写起来还挺繁琐,需要将各种情况都要考虑到,写了一个作为以后自己的工具吧. //获取哪一天 public static int getDay(Date d ...