大致的加载过程:

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)立即实例化该BeangetBean(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()方法

转载于:https://www.cnblogs.com/itxiaok/p/10356683.html

SpringIOC源码分析总结相关推荐

  1. 框架源码专题:springIOC的加载过程,bean的生命周期,结合spring源码分析

    文章目录 1.BeanFactory和ApplicationContext的区别? 2. IOC与 Bean的加载过程 ①:初始化容器DefaultListableBeanFactory ②:创建读取 ...

  2. Spring注解源码分析

    我们知道如果想使用spring注解你需要在applicationContext.xml配置文件中设置context:component-scan base-package='xxx'这样spring会 ...

  3. spring源码分析第二天------spring系统概述以及IOC实现原理

    1.Spring5 概述 Spring 是一个开源的轻量级 Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架, 其目的是用于简化企业级应用程序开发. Spring ...

  4. spring 源码深度解析_spring源码解析之SpringIOC源码解析(下)

    前言:本篇文章接SpringIOC源码解析(上),上一篇文章介绍了使用XML的方式启动Spring,介绍了refresh 方法中的一些方法基本作用,但是并没有展开具体分析.今天就和大家一起撸一下ref ...

  5. 【Spring】IOC:基于注解的IOC容器初始化源码分析

    从 Spring2.0 以后的版本中,Spring 也引入了基于注解(Annotation)方式的配置,注解(Annotation)是 JDK1.5 中引入的一个新特性,用于简化 Bean 的配置,可 ...

  6. SSM源码分析之Spring05-DI实现原理(基于Annotation 注入)

    目录导航 前言 注解的引入 AnnotationConfigApplicationContext 对注解Bean初始化 AnnotationConfigApplicationContext注册注解Be ...

  7. 【mybatis源码】 mybatis底层源码分析

    [mybatis源码] mybatis底层源码分析 1.测试用例 2.开撸源码 2.1 SqlSessionFactory对象的创建与获取 2.2 获取SqlSession对象 2.3 获取接口的代理 ...

  8. 源码通透-mybatis源码分析以及整合spring过程

    源码通透-mybatis源码分析以及整合spring过程 mybatis源码分析版本:mybaits3 (3.5.0-SNAPSHOT) mybatis源码下载地址:https://github.co ...

  9. Spring IOC 容器源码分析

    Spring IOC 容器源码分析 创建时间: 2017-11-15 00:00:00 [TOC] Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring ...

最新文章

  1. 在SpringBoot启动类上添加ComponentScan出现springbootapplication already applies given @ComponentScan
  2. 微服务之API网关接口设计
  3. [leetcode] Recover Binary Search Tree
  4. 页面中用到iframe不能完全显示的解决方案
  5. 自适应表格连续字符换行及单行溢出点点点显示
  6. call() , apply() ,bind()的用法
  7. coursera 《现代操作系统》 -- 第八周 存储模型(2)
  8. 华为认证怎么考?华为认证考试费用是多少?
  9. 亲民地理第39期-佛山(2)南风古灶
  10. 小知识:移动硬盘打不开是什么原因造成的?
  11. 数学建模学习(75):全局敏感性分析Morris 方法
  12. 什么是结构化数据、半结构化数据、非结构化数据
  13. 不可不会的「反转链表」问题
  14. D. Bouncing Boomerangs
  15. 完成10亿元D轮融资,易快报成费控SaaS独角兽?
  16. 「教师资格证定期注册」相关答疑
  17. 统计综合指标有哪些?
  18. PS改变图像尺寸和分辨率保存为tif图片颜色变成黑色-解决办法
  19. 视频中场:中视频的复兴与前路
  20. CCC认证费用是多少?

热门文章

  1. 神经网络:你的大脑是一台计算机吗?
  2. 陪伴程序员的一条龙、一骑士 36 岁了!
  3. 从学术界到产业界,阿里云李飞飞谈数据库为何要开源? | 《新程序员》
  4. 为什么 M1 和 Mac 是绝配?
  5. 微信十年,张小龙下一步要干什么?
  6. JavaScript递归
  7. 区块链仅仅只是炒作吗
  8. Git 同一个Git HostName 配置多个sshkey
  9. 网络新高速:T比特网络技术实现成功测试
  10. Java 中如何使用 SQL 查询文本