在测试时,经常使用这种方式来创建spring容器

//创建基于注解的springIOC容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopBeanConfig.class);
//创建基于配置文件的springIOC容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-beans.xml");

无论哪种方式,最终都会调用AbstractApplicationContext的一个重要方法——refresh(),首先来看这个方法的spring源码

    @Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. Prepare this context for refreshing.
prepareRefresh(); // 2. Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3. Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// 4. Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // 5. Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // 6. 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. Check for listener beans and register them.
registerListeners(); // 11. Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // 12. Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

重点步骤简析 

1. prepareRefresh  准备刷新容器

  (1) initPropertySources()  自定义属性设置,空方法,留给子类继承

  (2) getEnvironment.validateRequiredProperties  首先获取环境配置,然后校验必需属性

  (3) this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);

初始化事件监听器

  (4) this.earlyApplicationEvents = new LinkedHashSet<>();  初始化早期事件

2. obtainFreshBeanFactory  获取组件工厂

  (1) refreshBeanFactory  新建一个组件工厂,类型为DefaultListableBeanFactory,

然后对这个组件工厂设置了一个序列化ID

  (2) getBeanFactory 返回刚刚创建的组件工厂

3. prepareBeanFactory  对组件工厂做各种预处理设置

  (1) 在组件工厂中设置类加载器、属性解析器等

  (2) 在组件工厂中添加部分组件后置处理器,例如ApplicationContextAwareProcessor、ApplicationListenerDetector

  (3) 在组件工厂中设置忽略自动注入的接口

  (4) 设置自动装配规则

  (5) 在组件工厂中注册一些组件,例如环境配置ConfigurableEnvironment

4. postProcessBeanFactory  组件工厂的后置处理工作

5. invokeBeanFactoryPostProcessors 执行组件工厂后置处理器

  这一步是在组件工厂的标准初始化(1-4)之后进行的,主要是执行BeanFactoryPostProcessor及其子接口的

  BeanFactoryPostProcessor的子接口主要是指BeanDefinitionRegistryPostProcessor,可以向容器中注册新的组件,这个接口的特点是有两个方法,一个是自身的postProcessBeanDefinitionRegistry,另一个继承自BeanFactoryPostProcessor的postProcessBeanFactory,从源码可以看出,spring会先执行BeanDefinitionRegistryPostProcessor类型的组件的自身方法,然后执行其继承方法,最后才调用非BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor的后置处理方法

  (1) 从容器器中获取BeanDefinitionRegistryPostProcessor类型的组件

  (2) 将BeanDefinitionRegistryPostProcessor类型的组件按照顺序分类并排序,即是否实现了PriorityOrdered、Ordered接口

    (3) 依次执行实现了PriorityOrdered接口的、实现了Ordered接口的、没有实现任何顺序接口的组件的postProcessBeanDefinitionRegistry方法

  (4) 执行所有BeanDefinitionRegistryPostProcessor组件的postProcessBeanFactory方法

  (5) 从容器中获取其他的BeanFactoryPostProcessor类型的组件,即不是BeanDefinitionRegistryPostProcessor类型的

  (6) 剩下的步骤跟上面类似,就是先按照实现的顺序接口分类,在每个类别下排序,然后依次执行它们的postProcessBeanFactory方法

6. registerBeanPostProcessors 注册组件后置处理器,这种处理器用于拦截bean的创建过程

beanPostProcessor有很多子接口,每种子接口的执行时机各有不同

  |-DestructionAwareBeanPostProcessor

  |-InstantiationAwareBeanPostProcessor  

  |-MergedBeanDefinitionPostProcessor

  |-SmartInstantiationAwareBeanPostProcessor

  (1) 获取所有的beanPostProcessor的组件名

(2) 将所有的组件按优先顺序分为三类:

     |-实现了PriorityOrdered接口的列表priorityOrderedPostProcessors

     |-实现了Ordered接口的列表orderedPostProcessors

       |-没有实现任何顺序接口的列表nonOrderedPostProcessors

      还有一种特殊情况,凡是MergedBeanDefinitionPostProcessor类型的,都放在internalPostProcessors中

    (3) 注册priorityOrderedPostProcessors

  (4) 注册orderedPostProcessors

  (5) 注册nonOrderedPostProcessors

  (6) 注册internalPostProcessors

  (7) 注册ApplicationListenerDetector,它的作用是在组件初始化之后判断其是否为

ApplicationListner类型,如果是,则将其添加进容器的监听器集合

7. initMessageSource 初始化消息源组件,用于消息绑定、消息解析等功能,并且提供国际化解决方案

  (1) 获取beanFactory

  (2) 判断beanFactory中是否包含id为messageSource的组件

  (3) 如果已存在,则赋值给容器的messageSource属性,这种情况是我们自己在容器中注册了这个组件

  (4) 如果不存在,则新建一个DelegatingMessageSource,并赋值给容器的messageSource属性,

然后在beanFactory中注册这个新组件,并设置其id为messageSource

8. initApplicationEventMulticaster 初始化事件广播器

  (1) 获取beanFactory

  (2) 判断beanFactory中是否存在id为applicationEventMulticaster的组件

  (3) 如果已存在,则赋值给容器的applicationEventMulticaster属性,这种情况是我们自己在容器中注册了这个组件

  (4) 如果不存在,则新建一个SimpleApplicationEventMulticaster,并赋值给容器的

applicationEventMulticaster属性,然后在beanFactory中注册这个新组件,

并设置其id为applicationEventMulticaster

9. onRefresh 没有任何操作,留给子类继承的,我们可以自定义子容器,在重写方法中做一些我们想要的操作

10. registerListeners 注册事件监听器

  (1) 获取容器的属性applicationListeners,这是一个事件监听器的集合,将集合中的每个元素都添加进事件广播器

  (2) 从容器中获取所有ApplicationListener类型的组件,将这些组件添加进事件广播器

  (3) 发布早期事件,即容器的earlyApplicationEvents属性(参考第1(4)步),然后清空早期事件

11. finishBeanFactoryInitialization 完成剩下的单实例bean的初始化

  (1) 进入DefaultListableBeanFactory.preInstantiateSingletons方法,获取容器中所有的组件id列表

  (2) 遍历组件id列表,对每个组件,获取其组件定义信息,即RootBeanDefinition

  (3) 从组件定义信息中筛选掉抽象类、非单实例、懒加载的,这些bean在创建容器时并不初始化,

另外还有工厂组件,即实现了FactoryBean接口的,需要另外一套逻辑进行初始化

  (4) 从缓存中获取单实例bean,即DefaultSingletonBeanRegistry类的singletonObjects属性,所有被创建过的

单实例bean都会被缓存在这个映射中;如果缓存中存在,说明这个组件之前被创建过,直接返回

  (5) 如果缓存中不存在,则开始新建

     ① 将组件标记为已创建,即将其id存入AbstractBeanFactory的alreadyCreated属性中

     ② 获取组件的定义信息,即RootBeanDefinition

     ③ 从定义信息中获取该组件依赖的组件,如果存在,则重新从第11(4)步开始执行,创建这些依赖的组件

     ④ 创建完依赖组件(如果存在)之后,以下开始正式新建目标组件

     ⑤ 给组件后置处理器一个机会用代理对象代替目标对象,即执行InstantiationAwareBeanPostProcessor

类型的组件后置处理器的postProcessBeforeInstantiation、postProcessAfterInitialization方法

       ⑥ Allow post-processors to modify the merged bean definition,即执行

MergedBeanDefinitionPostProcessor类型组件后置处理器的postProcessMergedBeanDefinition方法

     ⑦ 执行AbstractAutowireCapableBeanFactory.populateBean方法,即属性赋值

在属性赋值之前,首先拿到InstantiationAwareBeanPostProcessor类型的组件后置处理器,

       并执行postProcessAfterInstantiation、postProcessProperties、postProcessPropertyValues方法;

       然后才执行该类的applyPropertyValues方法,利用反射调用组件的setter方法进行属性赋值

     ⑧ 执行以下三种aware接口的方法:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

     ⑨ 执行组件后置处理器的初始化前方法,即BeanPostProcessor.postProcessBeforeInitialization

⑩ 执行组件的初始化方法,即InitializingBean.afterPropertiesSet,以及在容器中自定义的initMethod

      ⑪ 执行组件后置处理器的初始化后方法,即BeanPostProcessor.postProcessAfterInitialization

       ⑫ 如果需要,注册组件的销毁方法,例如DisposableBean.destroy,以及在容器中自定义的destroyMethod

这里只是注册,并不调用

  (6) 通过第11(5)步,单实例bean已经创建并初始化完成,接着,会调用AbstractBeanFactory的父类方法——

     DefaultSingletonBeanRegistry.getSingleton方法,将新建的bean存入singletonObjects属性中,即缓存

  (7) 回到DefaultListableBeanFactory.preInstantiateSingletons方法(见第11(1)步)

       如果新建的bean实现了SmartInitializingSingleton接口,则执行afterSingletonsInstantiated回调方法

12. finishRefresh 完成容器刷新

  (1) 初始化生命周期处理器(LifecycleProcessor),先从BeanFactory中按类型获取,

如果没有就新建一个DefaultLifecycleProcessor,并注册进BeanFactory

  (2) 获取上一步注册的生命周期处理器,回调其onRefresh方法

  (3) 发布容器刷新事件,即ContextRefreshedEvent

SpringIOC容器创建过程的更多相关文章

  1. SpringMVC——DispatcherServlet的IoC容器(Web应用的IoC容器的子容器)创建过程

    在上一篇<Spring--Web应用中的IoC容器创建(WebApplicationContext根应用上下文的创建过程)>中说到了Web应用中的IoC容器创建过程.这一篇主要讲Sprin ...

  2. Spring源码解析 – AnnotationConfigApplicationContext容器创建过程

    Spring在BeanFactory基础上提供了一些列具体容器的实现,其中AnnotationConfigApplicationContext是一个用来管理注解bean的容器,从AnnotationC ...

  3. Spring容器创建过程

    Spring容器的refresh()   创建刷新 1  prepareRefresh() 刷新前的预处理 1) initProPertySources() 初始化一些属性设置: 子类定义个性化的属性 ...

  4. Spring-IOC bean 创建过程中的 ObjectFactory

    AbstractBeanFactory中doGetBean方法里有一段拿到RootBeanDefinition后,实例化该bean的方法 // Create bean instance. if (mb ...

  5. 100行代码撸完SpringIOC容器

    用过Spring框架的人一定都知道Spring的依赖注入控制反转;通俗的讲就是负责实例化对象 和 管理对象间的依赖 实现解耦. 我们来对比两段代码: UserController{ UserServi ...

  6. 三种方式创建bean对象在springIOC容器中初始化、销毁阶段要调用的自定义方法

    1. 使用@Bean注解定义initMethod和destroyMethod 所谓initMethod和destroyMethod,是指在springIOC容器中,对于bean对象执行到初始化阶段和销 ...

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

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

  8. 【转】Spring学习---SpringIOC容器的初始化过程

    [原文]https://www.toutiao.com/i6594400249429623304/ SpringIOC容器的初始化过程 简单来说,IoC容器的初始化是由refresh()方法来启动的, ...

  9. Spring IOC容器创建bean过程浅析

    1. 背景 Spring框架本身非常庞大,源码阅读可以从Spring IOC容器的实现开始一点点了解.然而即便是IOC容器,代码仍然是非常多,短时间内全部精读完并不现实 本文分析比较浅,而完整的IOC ...

随机推荐

  1. 69. Sqrt(x) (JAVA)

    Implement int sqrt(int x). Compute and return the square root of x, where x is guaranteed to be a no ...

  2. 关于mysql的查询优化

    由于工作原因,最近甲方客户那边多次反应了他们那边的系统查询速度慢,经过排除之后,发现他们那边的数据库完全没有用到索引,简直坑得一笔,通过慢查询日志分析,为数据表建立了适当的索引之后,查询速度明显的提高 ...

  3. laravel 中数据库查询结果自动转数组

    今天在项目中再次碰见laravel中从数据库中查询到的结果是对象,用toArray也不好用,之前改过一次,印象中是在/confing/database.php,    'fetch' => PD ...

  4. 分布式配置中心(Spring Cloud Config) (问题解答)

    转载:https://blog.csdn.net/forezp/article/details/70037291 1.foo是博主随意写的,实际是没有对应的文件.如果真有文件,返回的json在会有so ...

  5. ZROI 19.08.03 DP入门

    \(n\)个点,要求连一棵树,设点\(i\)的度数为\(d_i\),则其贡献为\(f(d_i)\mod 59393\),其中\(f(x)\)是一个\(k\)次多项式.最大化总贡献.\(n\leq 30 ...

  6. selenium操作下拉选和网页提示框

    import time from selenium import webdriver from selenium.webdriver.support.select import Select#处理下拉 ...

  7. 指数家族-Beta分布

    2. Beta分布 2.1 Beta分布 我们将由几个问题来得引出几个分布: 问题一:1:  2:把这个  个随机变量排序后得到顺序统计量  3:问  是什么分布 首先我们尝试计算  落在一个区间   ...

  8. 搭建 MySQL 5.7.19 主从复制,以及复制实现细节分析

    主从复制可以使MySQL数据库主服务器的主数据库,复制到一个或多个MySQL从服务器从数据库,默认情况下,复制异步; 根据配置,可以复制数据库中的所有数据库,选定的数据库或甚至选定的表. Mysql ...

  9. 【NOIP2016提高A组五校联考2】tree

    题目 给一棵n 个结点的有根树,结点由1 到n 标号,根结点的标号为1.每个结点上有一个物品,第i 个结点上的物品价值为vi. 你需要从所有结点中选出若干个结点,使得对于任意一个被选中的结点,其到根的 ...

  10. Help library 安装arcobjects for .NET异常问题

    新建一个reg文件写入,也可以导出一个reg文件在上面重新写入. Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\CLSID\{9DAA ...