引言

Spring容器就像一台构造精妙的机器,我们通过配置文件向机器传达控制信息,机器就能够按照设定的模式工作。如果将Spring容器比作一辆车,那么可以将BeanFactory看成汽车的发动机,而ApplicationContext则是一辆完整的汽车,它不但包括发动机,还包括离合器、变速器及底盘、车身、电气设备等其他组件。在ApplicationContext内,各个组件按部就班、有条不絮地完成汽车的各项功能。

内部工作机制

Spring的AbstractApplicationContext是ApplicationContext的抽象实现类,该抽象类的refresh()方法定义了Spring容器在加载配置文件后的各项处理过程,这些处理过程清新地刻画了Spring容器启动时所执行地各项操作:

       @Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // 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. 初始化BeanFactory:根据配置文件实例化BeanFactory,在obtainFreshBeanFactory()方法中,首先调用refreshBeanFactory()方法刷新BeanFactory,然后调用getBeanFactory()方法获取BeanFactory,这两个方法都是由具体子类实现。在这一步里,Spring将配置文件的信息装入容器的Bean定义注册表(BeanDefinitionRegistry)中,但是此时Bean还没有初始化;
  2. 调用工厂后处理器:根据反射机制从BeanDefinitionRegistry中找出所有实现了BeanFactoryPostProcessor接口的Bean,并调用其postProcessBeanFactory()接口方法;
  3. 注册Bean后处理器:根据反射机制从BeanDefintionRegistry中找出所有实现了BeanPostProcessor接口的Bean,并将它们注册到容器Bean后处理的注册表;
  4. 初始化消息源:初始化容器的国际化消息资源;
  5. 初始化应用上下文事件广播器;
  6. 初始化其他特殊的Bean:这是一个钩子方法。子类可以借助这个方法执行一些特殊的操作,如AbstractRefreshableWebApplicationContext就使用该方法执行初始化ThemeSource的操作;
  7. 注册事件监听器;
  8. 初始化所有单实例的Bean,使用懒加载模式的Bean初始化:初始化Bean后,将它们放入Spring容器的缓存池中;
  9. 初始化上下文刷新事件:创建上下文刷新事件,事件广播器负责将这些事件广播到每个注册的事件监听器中。

Spring容器从加载配置文件到创建一个完整Bean的作业流程及参与的角色

  1. ResourceLoader从存储介质中加载Spring配置信息,并使用Resource表示这个配置文件资源;
  2. BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中的每个< bean >解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
  3. 容器扫描BeanDefintionRegistry中的BeanDefintion,使用Java反射机制自动识别出Bean工厂后处理器(实现BeanFactoryPostProcessor接口的Bean),然后调用这些Bean工厂后处理对BeanDefinitionRegistry中的BeanDefinition进行加工处理。主要完成一下两项工作:

    1). 对使用占位符的< bean >元素标签进行解析,得到最终的配置值。这意味着对一些半成品式的BeanDefinition对象进行加工处理并得到成品的BeanDefinition对象;

    2). 对BeanDefinitionRegistry中的BeanDefinition进行扫描,通过Java反射机制找出所有属性编辑器的Bean(实现java.beans.PropertyEditor接口的Bean),并自动将它们注册到Spring容器的属性器注册表中(PropertyEditorRegistry)。
  4. Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,并调用InstantiationStarategy着手进行Bean实例化的工作;
  5. 在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装。BeanWrapper提供了很多以Java反射机制操作Bean的方法,它将结合该Bean的BeanDefintion及容器中的属性编辑器,完成Bean属性注入工作;
  6. 利用容器中的Bean后处理器(实现BeanPostProcessor接口的Bean)对己经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean;

小结

Spring容器堪称一部设计精密的机器,其内部拥有众多的组件和装置。Spring的高明之处在于,它使用众多接口描绘除了所有的装置的协作蓝图,构建好Spring的骨架,继而通过继承体系层层推演、不断丰富,最终让Spring成为有血有肉的完整的框架。所有在查看Spring框架的源码时,有两条清晰可见的脉络:

  1. 接口层描述了容器的重要组件及组件间的协作关系
  2. 继承体系逐步实现组件的各项功能。

接口层清晰地勾勒出Spring框架地高层功能,框架脉络呼之欲出。有了接口层抽象地描述后,不但Spring自己可以提供具体的实现,任何第三方组织也可以提供不同的实现,可以说Spring完善的接口层使框架的扩展性得到了很好的保证。纵向继承体系的逐步发展,分步骤地实现框架地功能,这种实现方案保证了框架功能不会堆积在某些类身上,从而造成过重地代码逻辑负载,框架的复杂度被完美地分解开了。

Spring容器技术内幕之内部工作机制的更多相关文章

  1. Spring容器技术内幕之BeanWrapper类介绍

    引言 org.springframework.beans.BeanWrapper是Spring框架中重要的组件类.BeanWrapper相当于一个代理器,Spring委托BeanWrapperwanc ...

  2. Spring容器技术内幕之BeanDefinition类介绍

    引言 org.springframework.beans.factory.config.BeanDefinition是配置文件< bean >元素标签在容器中地内部表示.< bean ...

  3. spring 内部工作机制(二)

    本章节讲Spring容器从加载配置文件到创建出一个完整Bean的作业流程及参与的角色. Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表, ...

  4. 【转】Java学习---HashMap和HashSet的内部工作机制

    [原文]https://www.toutiao.com/i6593863882484220430/ HashMap和HashSet的内部工作机制 HashMap 和 HashSet 内部是如何工作的? ...

  5. (spring-第5回【IoC基础篇】)spring容器从加载配置文件到实例化bean的内部工作机制

    前面讲过,spring的生命周期为:实例化前奏-->实例化-->实例化后期-->初始化前期-->初始化-->初始化后期-->bean的具体调用-->销毁前-- ...

  6. spring 内部工作机制(一)

    Spring内部机制的内容较多,所以打算多分几个阶段来写. 本章仅探索Spring容器启动做了哪些事: 前言: 都说Spring容器就像一台构造精妙的机器,此话一点不假,我们通过配置文件向机器传达控制 ...

  7. spring 容器技术入门

    官方文档 翻译 https://waylau.gitbooks.io/spring-framework-4-reference/content/III.%20Core%20Technologies/C ...

  8. Sring容器技术内幕之InstantiationStrategy类介绍

    引言 org.springframework.beans.factory.support.InstantiationStrategy负责根据BeanDefinition对象创建一个Bean实例.Spr ...

  9. Docker(二):理解容器编排工具Kubernetes内部工作原理

    一.Kubernetes是什么 要说到Docker就不得不说说Kubernetes.当Docker容器在微服务的环境下数量一多,那么统一的,自动化的管理自然少不了.而Kubernetes就是一个这样的 ...

随机推荐

  1. Linux 源码安装 FFmpeg

    加班次数频繁,已经快一年没有写博了.由于此次在项目中使用到了 FFmpeg 来处理音视频,顾记录下在 Linux 系统中源码安装 FFmpeg 以便不时之需. 1. 安装 yasm yasm 是一个汇 ...

  2. Java设计模式学习记录-迭代器模式

    前言 这次要介绍的是迭代器模式,也是一种行为模式.我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/ ...

  3. netty源码解解析(4.0)-3 Channel的抽象实现

    AbstractChannel和AbstractUnsafe抽象类 io.netty.channel.AbstractChannel 从本章开始,会有大量的篇幅涉及到代码分析.为了能够清晰简洁的地说明 ...

  4. 手撕coreML之yolov2 object detection物体检测(含源代码)

    一些闲话: 前面我有篇博客 https://www.cnblogs.com/riddick/p/10434339.html ,大致说了下如何将pytorch训练的.pth模型转换为mlmodel,部署 ...

  5. .12-浅析webpack源码之NodeWatchFileSystem模块总览

    剩下一个watch模块,这个模块比较深,先大概过一下整体涉及内容再分部讲解. 流程图如下: NodeWatchFileSystem const Watchpack = require("wa ...

  6. [转]来扯点ionic3[7] LocalStorage的使用—以登录和注销为例

    本文转自:https://segmentfault.com/a/1190000012146400 一般意义上,一个互联网 APP 中的数据主自与服务器的交互,但是对于有些数据,我们希望获取到它们以后能 ...

  7. 一个比较好用的省内存的ORM

    http://www.52chloe.com 记录一下,完了,就这样

  8. Hadoop小知识点总结1

    1.数据仓库warehouse一般不做更改,只做查询 2.OLTP:联机事务处理,比如:转账 OLAP:联机分析处理,比如:只做查询 3.hadoop的思想来源: GFS (Google的文件系统)即 ...

  9. Java 面向对象编程小练习(曾经)

    最近打算将之前学习过的小练习分享出来,算是巩固知识.虽然是小练习,但是越看越觉得有趣,温故而知新. 练习:功能跳水比赛,8个评委评分.运动员成绩去掉最高和最低之后的平均分 代码实例: 1.导包 imp ...

  10. 大数据之 Spark

    1 渊源 于2009由Matei Zaharia创立了spark大数据处理和计算框架,基于内存,用scala编写. 2 部署 2.1 需要软件包 下载路径见已有博文 Jdk ——因为运行环境为jvm ...