跳到主要内容

IoC 容器

IoC 容器、Bean 可重用组件

IoC 容器

Spring Framework 中最重要的两个概念:

  • 控制反转(Inversion of Control,IoC)
  • 面向切面编程(Aspect Oriented Programming,AOP)

什么是 IoC 容器?

什么是容器?

以下摘录廖雪峰的教程1

容器是一种为某种特定组件的运行提供必要支持的一个软件环境。例如,Tomcat 就是一个 Servlet 容器,它可以为 Servlet 的运行提供运行环境。类似 Docker 这样的软件也是一个容器,它提供了必要的 Linux 环境以便运行一个特定的 Linux 进程。

通常来说,使用容器运行组件,除了提供一个组件运行环境之外,容器还提供了许多底层服务。例如,Servlet 容器底层实现了 TCP 连接,解析 HTTP 协议等非常复杂的服务,如果没有容器来提供这些服务,我们就无法编写像 Servlet 这样代码简单,功能强大的组件。早期的 JavaEE 服务器提供的 EJB 容器最重要的功能就是通过声明式事务服务,使得 EJB 组件的开发人员不必自己编写冗长的事务处理代码,所以极大地简化了事务处理。

Spring 的核心就是提供了一个 IoC 容器,它可以管理所有轻量级的 JavaBean 组件,提供的底层服务包括组件的生命周期管理、配置和组装服务、AOP 支持,以及建立在 AOP 基础上的声明式事务服务等。”

什么是 IoC 容器?

IoC 容器(Inversion of Control)定义:一种可以自动化完成 Java 对象依赖注入的框架或容器,通常被用于管理对象之间的依赖关系、生命周期和配置信息等任务。在 Spring 框架中,Ioc 容器负责创建、管理和装配 Bean,使用者无需手动管理对象之间的耦合关系。

Spring Framework 的 IoC 容器称为 Spring 容器

控制反转、依赖注入

控制反转:一种决定容器如何装配组件的模式。只要遵循控制反转,按照一定的规则,容器就能将组件组装起来。而这里所谓的容器,就是用来创建组件并对它们进行管理的地方。

组件之间的依赖关系原先是由组件自己定义的,并在其内部维护,而现在这些依赖被定义在容器中,由容器来统一管理,并据此将其依赖的内容注入组件中。

在好莱坞,演艺公司具有极大的控制权,艺人将简历投递给演艺公司后就只能等待,被动接受演艺公司的安排。这就是知名的 好莱坞原则。IoC 容器背后的思想正是好莱坞原则,即 所有的组件都要被动接受容器的控制

Martin Fowler2 那篇著名的“Inversion of Control Containers and the Dependency Injection pattern”3 中提到“控制反转”不能很好地描述这个模式,“依赖注入”(Dependency Injection)能更好地描述它的特点。于是,我们经常会看到这两个词一同出现。

"As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection."

IoC 容器作用

将业务对象(即 组件,在 Spring 中这些组件被称为 Bean4)和关于组件的配置元数据(比如依赖关系)输入 Spring 容器中,容器就能为我们组装出一个可用的系统 —— 这就是 IoC 容器的作用:

容器的初始化

Spring 容器需要配置元数据和业务对象,因此在初始化容器时,我们需要提供这些信息。

两种配置方式:

  1. 基于注解的配置
  2. 基于 Java 类的配置

早期的配置元数据只能以 XML 配置文件的形式提供,从 2.5 版本开始,才可以以 XML 以外的配置方式地提供

容器初始化的大致步骤如下:

  1. 从 XML 文件、Java 类或其他地方加载配置元数据
  2. 通过 BeanFactoryPostProcessor 对配置元数据进行一轮处理
  3. 初始化 Bean 实例,并根据给定的依赖关系组装对象
  4. 通过 BeanPostProcessor 对 Bean 进行处理,期间还会触发 Bean 被构造后的回调方法

Bean 可重用组件

什么是 Bean?

JavaBeans5 是 Java 中比较重要的概念,而 Bean 也是 Spring 容器中的重要概念。

JavaBeans 是 Java 中一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点是可序列化,提供无参构造器,提供 getter 方法和 setter 方法访问对象的属性。名称中的“Bean”是用于 Java 的可重用软件组件的惯用叫法。

要成为 JavaBean 类别,则必需遵循关于命名、构造器、方法的特定规范。有了这些规范,才能有可以使用、复用、替代和连接 JavaBeans 的工具。

规范如下:

  • 有一个 public 的无参数构造函数
  • 属性可以透过 get、set、is(可替代 get,用在布尔型属性上)方法或遵循特定命名规则的其他方法访问
  • 可序列化6

Bean 是 Java 中的可重用软件组件,Spring 容器也遵循这一惯例,因此 将容器中管理的可重用组件称为 Bean。容器会根据所提供的元数据来创建并管理这些 Bean,其中也包括它们之间的依赖关系。Spring 容器对 Bean 并没有太多的要求,无须实现特定接口或依赖特定库,只要是最普通的 Java 对象即可,这类对象也被称为 POJO(Plain Old Java Object)7

POJO stands for Plain Old Java Object. It is an ordinary Java object, not bound by any special restriction other than those forced by the Java Language Specification and not requiring any classpath.

JavaBeans 示例:

// 注:"可序列化" —— 实现 Serializable 接口
public class PersonBean implements java.io.Serializable {
private boolean decesed = false;
private String name = null;

// 注:有一个 public 的无参数构造函数
public PersonBean() {
}

// 注:属性可以透过 get、set、is 方法访问
public boolean isDeceased() {
return deceased;
}

public void setDeceased(boolean value) {
deceased = value;
}

public String getName() {
return name;
}

public void setName(final String value) {
this.name = value;
}
}

Bean 依赖关系

在 Spring 容器中,“管理依赖”主要就是管理 Bean 之间的依赖。

有两种基本的注入方式:

  • 基于构造方法的注入
  • 基于 Setter 方法的注入

Bean 配置方式

配置方式有以下几种:

  • 基于 XML 文件的配置
  • 基于注解的配置
  • 基于 Java 类的配置

Bean 生命周期

一个 Bean 先要经过 Java 对象的创建(也就是通过 new 关键字创建一个对象),随后根据容器里的配置注入所需的依赖,最后调用初始化的回调方法,经过这三个步骤才算完成了 Bean 的初始化。若不再需要这个 Bean,则要进行销毁操作,在正式销毁对象前,会先调用容器的销毁回调方法。

Bean 的生命周期概括为 4 个阶段8

  • 实例化(Instantiation)
  • 属性赋值(Populate)
  • 初始化(Initialization)
  • 销毁(Destruction)

Spring Bean 生命周期,好像人的一生9

参考

Footnotes

  1. IoC 容器 - 廖雪峰的官方网站: https://www.liaoxuefeng.com/wiki/1252599548343744/1266265100383840

  2. About Martin Fowler: https://martinfowler.com/aboutMe.html

  3. Inversion of Control Containers and the Dependency Injection pattern: https://martinfowler.com/articles/injection.html

  4. Java 中 的 Bean 是一个由框架管理的、用于封装业务逻辑或数据的对象,它强调了配置与代码的分离、依赖关系的自动管理,以及对象生命周期的控制,从而简化了应用程序的开发和维护

  5. JavaBeans - Wikipedia: https://en.wikipedia.org/wiki/JavaBeans

  6. Java 中的序列化是一种机制,它允许将 Java 对象转换成一组字节(一个字节序列),这样就可以将这个字节序列写入到文件、数据库或通过网络进行传输。这个过程称为序列化(Serialization)。相反地,将这个字节序列重新转换回Java对象的过程则称为反序列化(Deserialization)

  7. Plain old Java object - Wikipedia: https://en.wikipedia.org/wiki/Plain_old_Java_object

  8. 如何记忆 Spring Bean 的生命周期 - 掘金: https://juejin.cn/post/6844904065457979405

  9. Spring Bean 生命周期,好像人的一生。。 - 掘金: https://juejin.cn/post/7075168883744718856