美文网首页后端开发进阶之路Java技术升华我爱编程
【框架探秘】Spring 专题 01. IoC 容器及其原理

【框架探秘】Spring 专题 01. IoC 容器及其原理

作者: 程序之心 | 来源:发表于2018-02-10 13:29 被阅读40次

    Spring 在 Java 开发中应用广泛,已成为 Java 领域的基础设施。从这篇文章开始,开启一个 Spring 技术专题,进行总结和解读。

    控制反转和依赖注入  

    控制反转,英文名称 Inversion of Controller,缩写为 IoC,来源于 1988 年 Ralph E. Johnson 和 Brian Foote 的论文 Designing Reusable Classes。控制反转的核心在于一个对象所依赖的其他对象由外部传递给它,而不是自己去创建。也就是说,对象获取自己依赖的对象的控制权反转了,自己无法决定。

    依赖注入,英文名称 Dependency Injection,缩写为 DI,是指将实例变量传入到一个对象中去。依赖注入是控制反转的一种实现方式,还有一种实现方式是服务定位 (Service Locator)。

    Spring 最核心的功能便是依赖注入。基于 Spring 框架进行软件开发,由 Spring 来注入变量,比如只依赖于接口而不是具体的实现类、把参数值或依赖关系存储在配置文件中,可以极大地减少耦合。依赖注入的实现需要一个容器来存储所有的 Java 对象,在 Spring 中这个容器便是 IoC 容器。

    IoC 容器的主要组件  

    Spring 中 IoC 容器的基础包是 org.springframework.beans 和 org.springframework.context。IoC 容器包含 BeanFactory 和 ApplicationContext 两个接口及其实现。其中 BeanFactory 提供 IoC 的基本功能,ApplicationContext 增加了很多功能能够支持上下文、AOP、资源处理、国际化、事件等,是 BeanFactory 的子接口。通常开发中,使用 ApplicationContext。

    IoC 容器根据配置创建并管理 Bean,是通过读取 Bean 配置来生成相应的对象。Bean 配置可以是注解,如 @Bean,也可以存储在配置文件中,如 xml、properties 文件。配置文件中的配置,在 IoC 中被统一看成是资源,路径可以是 ClassPath、FileSystem、URL、jar 等。Bean 配置的读取是通过 BeanDefinitionReader 载入,转换成 Spring 内部描述对象 BeanDefinition,然后通过 BeanRegister 注册到容器 BeanFactory 中的。因此,IoC 容器的核心在于 6 个重要组件:

    ResourceLoader:资源加载组件,加载资源文件的内容,如 xml、properties 并解析;

    Resource:资源组件,描述通过 ResourceLoader 加载的文件内容;

    BeanFactory:Bean 工厂,实际上是 IoC 的核心容器,负责存储和管理 Bean;

    BeanDefinitionReader:读取 Resource 对象转换成 BeanDefinition;

    BeanDefinition:描述 Bean 的定义;

    SingletonBeanRegister/AliasRegister:把 BeanDefinition 描述的 Bean 注册到 BeanFactory 中。

    ResourceLoader 负责加载 xml、properties 等文件资源,返回一个资源 Resource 对象。在 Spring 中,有多种类型的 ResourceLoader,可以从文件系统、ClassPath、jar 包等多种来源中进行加载,主要的 ResourceLoader 及其继承关系如下图所示(图片来自网络)。

    Resource 是 Spring 对各种资源的统一描述,由 ResourceLoader 加载资源文件后生成 Resource 对象。Spring 中有多种 Resource 类型,比如 ClassPathResource 用于描述 ClassPath 中的资源、FileSystemResource 用于描述文件系统中的资源、UrlResource 用于描述从 URL 加载的资源,还有 InputStreamResource、ByteArrayResource 等。各个类型的关系如下所示(图片来自网络)。

    BeanFactory 是 Spring 中的 Bean 工厂,装着 Bean 对象以及所需要的各种数据,是 Spring IoC 的核心。BeanFactory 仅仅只是一个 Bean 容器,而 ApplicationContext 在继承 BeanFactory 的基础上又增加了 EnvironmentCapable、MessageSource、ApplicationEventPublisher 等扩展功能,成为与上下文环境息息相关的容器。同时 ApplicationContext 还有与应用上下文有关的多种实现类,比如 ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、WebApplicationContext 等,分别用于支持各种环境的上下文。BeanFactory 及 ApplicationContext 相关的类型和关系如图所示(图片来自网络)。

    BeanDefinitionReader、BeanDefinition、SingletonBeanRegister/AliasRegister 是 Resource 和 BeanFactory 之间的桥梁。

    BeanDefinitionReader 根据 Resource 对象,把资源转换成 BeanDefinition ,完成从资源(包括定义、配置、数据等)到 Spring 内部 Bean 描述的转换。BeanDefinitionReader 主要有两种实现,XmlBeanDefinitionReader 用于转换 XML 资源中的数据,PropertiesBeanDefinitionReader 用于转换 properties 文件中的数据。

    BeanDefinition 有多种接口和类型,这里不需要过多描述。

    IoC 的组件并不是互相独立的,它们之间有着复杂的调用和依赖关系,在后面的启动过程中,我们将看到各个组件通力合作。

    IoC 容器的启动过程   

    IoC 容器的启动过程,可以分为两个阶段,容器启动阶段和 Bean 实例化阶段。在容器启动阶段,Spring 从资源中加载配置信息、解析配置信息、装配 BeanDefinition、后处理;在 Bean 实例化阶段,Spring 进行实例化对象、装配依赖、生命周期回调、对象其他处理和注册回调接口。整个流程可以用下面的图表示(图片来自网络)。

    加载和解析配置信息就是从配置文件中读取信息并转化为 Spring 内部描述。 这一步主要是 ResourceLoader 在工作,解析出 Resource。

    装配 BeanDefinition 就是 BeanDefinitionReader 从 Resource 中解析出描述,生成 BeanDefinition 的过程。

    后处理是一个允许我们在启动流程中进行定制操作的阶段。这个阶段在得到 BeanDefinition 之后,通常我们通过实现 BeanFactoryPostProcessor 的接口来进行定制操作,比如修改 BeanDefinition 的定义。

    容器启动完成后,Spring 开始实例化 Bean。实例化 Bean 对象就是创建 Java 对象,如有构造器注入定义则使用构造器注入的规则创建 Java 对象,然后进行setter 、autowired 依赖注入。

    依赖注入完成后,Spring 开始处理 Bean 生命周期的回调,比如调用 xml 中 init-method 或注解 PostConstruct 定义的初始化方法进行自定义的 Bean 初始化。Spring 提供了 BeanPostProcessor 接口,我们可以使用这个接口干预 Bean 的初始化过程,在初始化之前和之后进行定制操作。

    对象其他处理阶段主要是其他功能的实现,比如通过实现 Spring 定义的一个接口来获取上下文或者其他操作。注册回调接口则是把 Bean 实现的功能接口注册到上下文中,比如事件发送与接收等。

    至此,IoC 容器已经可以直接使用了。通过 getBean 方法即可获取 IoC 容器中的 Bean 对象。如果一个 Bean 对象不是单例的,则在 getBean 时进行实例化对象和依赖注入。

    关于 IoC 的更多实现原理,将在后续的系列文章中讨论,欢迎关注下一篇文章《【框架探秘】Spring 专题 02. IoC 容器依赖注入原理》。

    分享学习笔记和技术总结,内容涉及 Java 技术、软件架构、前沿技术、开源框架、数据结构与算法、编程感悟等多个领域,更多文章等待您的阅读。本文首发于微信公众号“后端开发那点事儿” 。

    相关文章

      网友评论

        本文标题:【框架探秘】Spring 专题 01. IoC 容器及其原理

        本文链接:https://www.haomeiwen.com/subject/ecictftx.html