参考书籍:《Spring技术内幕》

系列文章

Spring IOC(一):概述

Spring IOC(二):初始化

Spring IOC(三):依赖注入

Spring IOC(四):相关特性

2 IOC 容器系列的设计与实现:BeanFactoryApplicationContext

在Spring IoC容器的设计中,我们可以看到两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本功能;另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配。有了这两种基本的容器系列,基本上可以满足用户对IoC容器使用的大部分需求了。

2.1 Spring IOC 容器系列

具体什么是IOC容器呢?它在Spring框架中到底长什么样?其实对IoC容器的使用者来说,我们经常接触到的
BeanFactoryApplicationContext都可以看成是容器的具体表现形式。如果深入到Spring的实现中去看,我们通常所说的IoC容器,实际上代表着一系列功能各异的容器产品,只是容器的功能有大有小,有各自的特点。我们以水桶为例,在商店中出售的水桶有大有小,制作材料也各不相同,有金属的、塑料的等,总之是各式各样的,但只要能装水,具备水桶的基本特性,那就可以作为水桶来出售,来让用户使用。这在Spring中也是一样,Spring有各式各样的IoC容器的实现供用户选择和使用。使用什么样的容器完全取决于用户的需要,但在使用之前如果能够了解容器的基本情况,那对容器的使用是非常有帮助的,就像我们在购买商品前对商品进行考察和挑选那样。从代码的角度入手,我可以看到关于这系列容器的设计情况。

在这些Spring提供的基本IoC容器的接口定义和实现的基础上,Spring通过定义BeanDefinition来管理基于Spring的应用中的各种对象以及它们之间的相互依赖关系。BeanDefinition抽象了我们对Bean的定义,是让容器起作用的主要数据类型。在计算机世界里,所有的功能都是建立在通过数据对现实进行抽象的基础上的。IoC容器是用来管理对象依赖关系的,对IoC容 器来说,BeanDefinition就是对依赖反转模式中管理的对象依赖关系的数据抽象,也是容器实现依赖反转功能的核心数据结构,依赖反转功能都是围绕对这个BeanDefinition的处理来完成的。这些BeanDefinition就像是容器里装的水,有了这些基本数据,容器才能够发挥作用。

2.2 Spring IOC 容器的设计

IOC容器接口设计图,描述了IOC容器中的主要接口设计。

  • 从接口BeanFactoryHierarchicalBeanFactory,再到ConfigurableBeanFactory是一条主要的BeanFactory的设计路径,在这条接口设计路径中BeanFactory定义了基本的IOC容器的规范。在这个接口定义中,包括了getBean()这样的IOC容器的基本方法。而HierarchicalBeanFactory接口在继承了BeanFactory接口之后,增加了getParentBeanFactory()的接口功能,使BeanFactory具备了双亲IOC容器的管理功能。再接下来的ConfigurableBeanFactory接口中主要定义了一些对BeanFactory的配置功能,比如通过setParentBeanFactory()设置双亲IOC容器,通过addBeanPostProcessor()设置bean的后置处理等。通过这些接口设计的叠加,定义了BeanFactory就是简单IOC容器的基本功能。
  • 第二条接口设计主线是从ApplicationContext应用上下文为核心的接口设计,这里涉及的接口设计有,从BeanFactoryListableBeanFactory再到ApplicationContext再到我们常用的WebApplicationContext或者ConfigurableApplicationContext接口。我们常用的应用上下文基本上都是ConfigurableApplicationContext或者WebApplicationContext的实现。在这个接口体系中ListableBeanFactoryHierarchicalBeanFactory连个接口,连接BeanFactory的接口定义和ApplicationContext的接口定义。在ListableBeanFactory接口中细化了很多BeanFactory的接口功能,比如定义了String[] getBeanDefinitionNames()接口方法,HierarchicalBeanFactory前面已经提到过主要是增加了双亲IOC的功能,ApplicationContext接口,它通过继承MessageSourceResourceLoaderApplicationEventPublisher接口,在BeanFactory简单IOC容器的基础上添加了许多对高级容器的特性的支持。
  • 这里涉及的主要接口关系,而具体的IOC容器都是在这个接口体系下实现的,比如**DefaultListableBeanFactory,这个基本IOC容器的实现就是实现了ConfigurableListableBeanFactory,从而成为一个简单IOC容器的实现**。像其他IOC容器,比如XmlBeanFactory,都是基于DefaultListableBeanFactory基础上做的拓展,同样的ApplicationContext的实现也是如此。
  • 这个接口系统是以BeanFactoryApplicationContext为核心的。而BeanFactory又是IOC容器的最基本接口,在ApplicationContext的设计中,一方面,可以看到它继承了BeanFactory接口体系中的ListableBeanFactoryAutowrieCapableBeanFactoryHierarchicalBeanFactoryBeanFactory接口,具备了BeanFactory IOC 容器的基本功能;另一方面,通过集成MessageSourceResourceLoaderApplicationEventPublisher这些接口,BeanFactoryApplicationContext赋予了更高级的IOC容器特性。对于ApplicationContext还设计了web环境下使用的WebApplicationContext接口。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DUyEiObN-1640346254229)(file://C:/Users/Function/AppData/Roaming/Typora/typora-user-images/1639708322628.png?lastModify=1640345739)]

2.2.1 BeanFactory的简单介绍

BeanFactory提供的是最基本的IoC容器的功能,关于这些功能定义,我们可以在接口BeanFactory中看到。

BeanFactory接口定义了IoC容器最基本的形式,并且提供了IoC容器所应该遵守的最基本的服务契约 ,同时,这也是我们使用IoC容器所应遵守的最底层和最基本的编程规范,这些接口定义勾画出了IoC的基本轮廓。很显然,在Spring的 代码实现中,BeanFactory只是一个接口类,并没有给出容器的具体实现。

DefaultListableBeanFactory , XmlBeanFactoryApplicationContext等 都可以看成是容器附加
**了某种功能的具体实现,也就是容器体系中的具体容器产品。**下面我们来看看BeanFactory是怎样定义IoC容器的基本接口的。

2.2.2 BeanFactory的设计原理

BeanFactory接口提供了使用IoC容器的规范。在这个基础上,Spring还提供了符合这个IoC容器接口的一系列容器的实现供开发人员使用。我们以XmlBeanFactory的实现为例来说明简单IoC容器的设计原理。如图所示为XmlBeanFactory设计的类继承关系。

可以看到,作为一个简单IoC容器系列最底层实现的XmlBeanFactory,与我们在Spring应用中用到的那些上下文相比,有一个非常明显的特点: 它只提供最基本的IoC容器的功能。理解这一点有助于我们理解ApplicationContext与基本的BeanFactory之间的区别和联系。我们可以认为直接的BeanFactory实现是IoC容器的基本形式,而各种ApplicationContext的实现是IoC容器的高级表现形式。

让我们好好地看一下图中的继承关系,从中可以清楚地看到类之间的联系,它们都是IoC容器系列的组成部分。在设计这个容器系列时,我们可以从继承体系的发展上看到IoC容器各项功能的实现过程。如果要扩展自己的容器产品,最好在继承体系中检查一下,看看Spring是不是已经提供了现成的或相近的容器实现供我们参考。下面就从我们比较熟悉的XmlBeanFactory的实现入手进行分析,来看看一个基本的IoC容器是怎样实现的。

XmlBeanFactory继承 自DefaultListableBeanFactory这个类,后者非常重要,是我们经常要用到的一个IoC容器的实现,比如在设计应用上下文ApplicationContext时就会用到它。我们会看到这个**DefaultListableBeanFactory实际上包含了基本IoC容器所具有的重要功能**,也是在很多地方都会用到的容器系列中的一个基本产品。

**在Spring中,实际上是把DefaultListableBeanFactory作为一个默认的功能完整的IoC容器来使用的XmlBeanFactory在继承 了 DefaultListableBeanFactory容器的功能的同时,增加了新的功能 **这些功能很容易从XmlBeanFactory的名字上猜到。它是一个与XML相关的BeanFactory,也就是说它是一个可以读取以XML文件方式定义的BeanDefinition的IoC容器。

这些实现XML读取的功能是怎样实现的呢? 对这些XML文件定义信息的处理并不是由XmIBeanFactory直接完成的。在XmlBeanFactory中 ,初始化了一个XmlBeanDefinitionReader对象,有了这个Reader对象(载入功能),那些以XML方式定义的BeanDefinition就有了处理的地方。我们可以看到,对这些XML形式的信息的处理实际,上是由这个XmlBeanDefinitionReader来完成的。

构造XmlBeanFactory这个loC容器时,需要指定BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类(定位功能)来给出。Resource是Spring用 来封装I/O操作的类。比如,我们的BeanDefinition信息是以XML文件形式存在的,那么可以使用像ClassPathResource res = new ClassPathResource("beans.xml");这样具体的ClassPathResource来构造需要的Resource,然后将Resource作为构造参数传递给XmlBeanFactory构造函数。这样,IoC容器就可以方便地定位到需要的BeanDefinition信息来对Bean完成容器的初始化和依赖注人过程。

XmlBeanFactory的功能是建立在DefaultListableBeanFactory这个基本容器的基础上的,并在这个基本容器的基础上实现了其他诸如XML读取的附加功能。对于这些功能的实现原理,看一看XmlBeanFactory的代码实现就能很容易地理解。在XmlBeanFactory构造方法中需要得到Resoorce对象。对XmlBeanDefinitionReader对象的初始化,以及使用这个对象来完成对loadBeanDefinitions的调用,就是这个调用启动从Resource中载入BeanDefinitions的过程,LoadBeanDefinitions 同时也是IoC容器初始化的重要组成部分。

public class XmlBeanFactory extends DefaultListableBeanFactory {private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);/*** Create a new XmlBeanFactory with the given resource,* which must be parsable using DOM.* @param resource the XML resource to load bean definitions from* @throws BeansException in case of loading or parsing errors*/public XmlBeanFactory(Resource resource) throws BeansException {this(resource, null);}/*** Create a new XmlBeanFactory with the given input stream,* which must be parsable using DOM.* @param resource the XML resource to load bean definitions from* @param parentBeanFactory parent bean factory* @throws BeansException in case of loading or parsing errors*/public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {super(parentBeanFactory);this.reader.loadBeanDefinitions(resource);}
}

我们看到XmlBeanFactory使用了DefaultListableBeanFactory作为基类,**DefaultListableBeanFactory是很重要的一个IoC实现,**在其他IoC容器中,比如ApplicationContext其实现的基本原理和XmlBeanFactory一样,也是通过持有或者扩展DefaultListableBeanFactory来获得基本的IoC容器的功能的。

参考XmlBeanFactory的实现,我们以编程的方式使用DefaultListableBeanFactory从中我们可以看到IoC容器使用的一些基本过程。尽管我们在应用中使用IoC容器时很少会使用这样原始的方式,但是了解一下这个基本过程,对我们了解IoC容器的工作原理是非常有帮助的。因为这个编程式使用容器的过程,很清楚揭示了在IoC容器实现中的那些关键的类(比如ResourceDefaultListableBeanFactoryBeanDefinitionReader) 之间的相互关系,例如它们是如何把IoC容器的功能解耦的,又是如何结合在一起为IoC容器服务的等等。

ClassPathResource res = new ClassPathResource ( "beans.xml");DefaultistableBeanFactory factory = new DefaultListableBeanFactory();XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);reader.loadBeanDefinitions(res);

在使用IoC容器时,需要如下几个步骤:

  1. 创建IoC配置文件的抽象资源,这个抽象资源包含了BeanDefinition的定义信息。
  2. 创建一个BeanFactory,这里使用DefaultListableBeanFactory
  3. 创建一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition,通过一个回调配置给BeanFactory.
  4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成。完成整个载入和注册Bean定义之后,需要的IoC容器就建立起来了。这个时候就可以直接使用IoC容器了。

2.2.3 ApplicationContext的简单介绍

ApplicationContext是一个髙级形态意义的loC容器。可以看到ApplicationContext还在BeanFactory基础上扩展了其他功能。

  • 支持不同的信息源。我们看到Applicationcontext扩展了MessageSource接口,这些信息源的扩展功能可以支持国际化的实现,为开发多语言版本的应用提供服务。
  • 访问资源。这一特性体现在对ResourceLoaderResource的支持上,这样我们可以从不同地方得到Bean定义资源。这种抽象使用户程序可以灵活地定义Bean定义信息,尤其是从不同的途径得到Bean定义信息。这在接口关系上看不出来,不过一般来说,具体ApplicationContext都是继承了DefaultResourceLoader的子类。因为
    DefaultResourceLoaderAbstractApplicationContext的基类。
  • 支持应用事件。继承了接口ApplicationEventPublisher从而在上下文中引入了事件机制。这些事件和Bean的生命周期的结合为Bean的管理提供了便利。

AppHcationContext中提供的附加服务。这些服务使得基本IoC容器的功能更丰富。因为具备了这些丰富的附加功能,使得ApplieationContext与简单的BeanFactory相比,对它的使用是一种面向框架的使用风格 ,所以一般建议在开发应用时使用ApplicationContext作为IoC容器的基本形式。

2.2.4 ApplicationContext的设计原理

以常用的FileSystemXmlApplicationContext的实现为例来说明ApplicationContext容器的设计原理。

FileSystemXmlApplicationContext的设计中,我们看到**Applicationcontext应用上下文的主要功能已经在 FileSystemXmlApplicationContext 的基类 AbstractXmlApplicationContext 中实现了**,在FileSystemXmlApplicationContext中,作为一个具体的应用上下文,只需要实现和它自身设计相关的两个功能:

(1)如果应用直接使用FileSystemXmlApplicationcontext对于实例化这个应用上下文的支持,同时启动IoC容器的refresh()过程。这在FileSystemApplicationComext的代码实现中可以看到,代码如下:

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();}}

这个refresh()过程会牵涉IoC容器启动的一系列复杂操作,同时,对于不同的容器实现,这些操作都是类似的,因此在基类(AbstractApplicationContext)中将它们封装好。所以,在FileSystemXmlApplicationContext的设计中看到的只是一个简单的调用。

(2) 另一部分与FileSystemXmlApplicationContext设计具体相关的功能,这部分与怎样从文件系统中加载XML的Bean定义资源有关。

通过这个过程,可以为在文件系统中读取以XML形式存在的BeanDefinitian做准备,因为不同的应用上下文实现对应着不同的读取BeanDefinition的方式,在FileSystemXmlApplicationContext中的实现代码如下:

@Overrideprotected Resource getResourceByPath(String path) {if (path.startsWith("/")) {path = path.substring(1);}return new FileSystemResource(path);}

Spring IOC(一):概述相关推荐

  1. Spring IOC 组件概述

    IOC 概述 IOC: Inversion of Control(控制反转), 这里其实指的是: 将程序中需要使用的 POJOs, 丢入到容器中, 解析成统一的 BeanDefinition(主要基于 ...

  2. Spring IoC(一)IoC容器的设计与实现:BeanFactory与ApplicationContext

    在写BeanFactory与ApplicationContext 之前,我想先简单聊一聊Spring IoC 容器,希望能给大家一个参考.如果你对这反面的知识比较了解,可以直接跳过. (一)Sprin ...

  3. 小马哥spring编程核心思想_求小马哥讲Spring栈核心编程思想 Spring IoC+Bean+Framework教程...

    这次搜集了下小马哥讲Spring栈核心编程思想 Spring IoC+Bean+Framework,最强Spring全面核心实战的视频教程,有需要的朋友可以自行下载学习. 课程简介: 小马哥出手的Sp ...

  4. Spring IOC和DI概述

    一.IOC和DI 1. IOC (Inversionof Control): 其思想是反转资源获取的方向.传统的资源查找方式要求组件向容器发起资源查找请求.作为回应,容器适时的返回资源. 而应用了IO ...

  5. Spring(2)——Spring IoC 详解

    Spring IoC 概述 IoC:Inverse of Control(控制反转) 读作"反转控制",更好理解,不是什么技术,而是一种设计思想,就是将原本在程序中手动创建对象的控 ...

  6. Spring IoC(二)IoC容器的初始化过程

    (一)IoC 容器初始化过程概述 1.1简要概述初始化过程 IoC 容器的初始化过程是通过refresh() 方法来启动的,这个方法标识着IoC 容器正式启动.具体来说,这个启动过程包括:BeanDe ...

  7. spring ioc原理解析

    概述 Spring IOC控制反转,分为两个方面解释: 控制:对象对于内部成员的控制 反转:将之前对象管理自己内部成员,转变为ioc容器管理,目的是接耦 IOC的好处是: 无需手动创建,拿来就用 享受 ...

  8. java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象?

    前面几篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注册我们定义的 bean 信息. 其中,「Spring 中的 IoC 容器」对 Spring 中的容器做了一个概述,「Sprin ...

  9. Spring —— IoC 容器详解

    引言 本篇博客总结自官网的<The IoC Container>,其中会结合王富强老师的<Spring揭秘>融入自己的语言和理解,争取通过这一篇文章彻底扫除spring IOC ...

最新文章

  1. 基于GAN模型的生成人脸重构、返老还童、看见前世今生(Age Progression/Regression)
  2. std::ostringstream::str()返回临时对象
  3. java超级简单贪吃蛇_java实现简易贪吃蛇游戏
  4. methodhandle_概览Java 7 MethodHandle及其用法
  5. html点击图片产生事件,jquery – 图像单击HTML5 Canvas中的事件
  6. python saml2 认证实例程序demo
  7. java 单文件上传_java – JIRA中的单个文件上传
  8. Java程序Date类型比较
  9. 尚硅谷和尚学堂的区别_在北京尚学堂学习的009天
  10. r语言去除字符串两端多余空格
  11. 验证码图片 java_验证码图片
  12. 关于ODBC使用SQL语句和调用存储过程传递参数的使用方式说明
  13. android 扫描照片功能,巧把安卓手机打造成扫描仪:拍照识别文档、手写笔记转PDF(图)...
  14. Java的System.out.println并不等于C的printf
  15. 布谷鸟哈希函数的参数_布谷鸟算法详细讲解
  16. 云计算认证哪个好?考什么内容?
  17. 微型计算机独立显卡,计算机显卡分为哪几类?有什么特点是?
  18. 悟--心智成熟的旅程
  19. 【JVAV】—继承、多态、抽象类
  20. igraph study

热门文章

  1. 两种常见的周期性特征,时序必知强特
  2. CCF系列题解--2018年3月第三题 URL映射
  3. ArcEngine实现要素类排序的四种方法
  4. FLINK 窗口实现原理
  5. Debug python - Segmentation fault (core dumped)
  6. 【报告分享】2021母婴行业白皮书-巨量引擎(附下载)
  7. HTML、SHTML、DHTML、XHTML、XML区别
  8. RSF 异步访问性能分析报告 - 百兆网卡下的彪悍性能
  9. Scroller全认知,对于Scroller 你真的了解吗?
  10. 面试:如何用最少的老鼠试出有毒的牛奶?