这个问题松哥想了很久要怎么和大家展开介绍,最早我是想整一篇文章把 Spring 容器整个从头到尾捋一遍,但是,东西太多显然不现实,我还是倾向于通过不同的文章,从不同的角度来介绍 Spring 容器的一些使用细节,最后再将整体串通起来~
因此,今天我想先和大家聊一个小的话题,就是我们先来捋一捋 Spring 中真正干活的容器到底是哪个?
说到 Spring 容器,我们很容易想到 BeanFactory,大家很容易拿到这张图:
这张图大致上一看,有七八个能干活的容器,难道 Spring 中真的有这么多种不同的容器吗?那我们不妨想一想,容器的核心职责是什么?我们是否真的需要这么多容器?
其实,Spring 中,跟 Bean 最核心的功能相关的容器,只有三个!接下来我们来分析一下。
BeanFactory 是所有容器的根,它里边提供了规范了最基本的容器方法和判断方法,例如如下一些方法:
BeanFactory 中常见的方法主要就是这些。这也是容器操作中最最核心的方法。
在本文一开始的类继承图中,BeanFactory 有很多实现类,那么是哪些实现类实现了上面这些方法呢?其实只有三个,分别是:
别看实现类很多,但是其实干活的就是这三个。
DefaultListableBeanFactory 是 Spring 框架中最常用的 bean 工厂之一。它是 BeanFactory 接口的一个实现类,同时也是 ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory 接口的实现类。DefaultListableBeanFactory 提供了丰富的功能来管理和访问 bean。
DefaultListableBeanFactory 的主要特点和功能包括:
总的来说,DefaultListableBeanFactory 是 Spring 框架中最常用的 Bean 工厂,它提供了丰富的功能来定义、配置、管理和访问 Bean,它的功能最完整也最成熟。它是实现依赖注入和控制反转 (IoC) 的核心组件之一。
我们平时开发用的各种“容器”其实都是 DefaultListableBeanFactory。
例如在松哥之前和大家讲的基本用法中,我们常用的两个类分别是 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext,这两个底层使用的容器其实就是 DefaultListableBeanFactory。
StaticListableBeanFactory 这个容器我们其实很少用到,但是这里大家也了解一下。
这个容器从名字上就能看出其特点:静态。不错,这是一个静态容器,它里边定义了一个 Map 集合,当你想要存储一个 Bean 的时候,它就给你存到这个 Map 集合中,当你想要获取一个 Bean 的时候,它就给你从这个 Map 集合中读取出来。
StaticListableBeanFactory 的主要特点和功能包括:
总的来说,StaticListableBeanFactory 提供了一种静态且列表化的方式来管理和访问 Bean。它适用于那些在运行时不需要动态修改 Bean 的应用场景,并且提供了方便的方法来获取和操作 Bean 的列表信息。
SimpleJndiBeanFactory 是 Spring 框架中的一个类,它是 BeanFactory 接口的一个实现类。SimpleJndiBeanFactory 使用简单的 JNDI (Java Naming and Directory Interface) 技术来管理和访问 Bean。
JNDI 是 Java 平台提供的一种标准 API,用于访问命名和目录服务。
SimpleJndiBeanFactory 利用 JNDI 的功能,可以从 JNDI 中查找和获取 Bean,以及执行与 JNDI 相关的操作。
SimpleJndiBeanFactory 的主要特点和功能包括:
老实说,这个 SimpleJndiBeanFactory 最大的特点就是利用了 JNDI 技术,然而,我们平时开发实际上很少会用到 JNDI 技术,所以这个容器其实用的并不多。
Spring 中的基础容器就这三个,其中被大量使用的是第一个 DefaultListableBeanFactory。
如果前面所说的三个容器(BeanFactory)是一个发动机,那么 ApplicationContext 就是一辆汽车,回顾本文一开始的类结构图,其实除了前面三个 BeanFactory 之外,其他的都算是 ApplicationContext 了。
BeanFactory 提供了 Bean 的核心功能,但是依然缺乏很多东西,例如配置文件要怎么加载?带注解的类谁去扫描?国际化怎么实现?事件的处理等等。。。这些功能上面三个核心类都没有!那么谁有呢?那就是 ApplicationContext 有。另外,Spring 中许多通过 BeanPostProcessor 实现的功能,通过 BeanFactory 也无法实现,因为直接使用 BeanFactory 并不会触发 BeanPostProcessor,如果非要使用,得自己手动去触发这些后置处理器的执行。
ApplicationContext 并非一个全新的容器,本质上,它里边使用的是 DefaultListableBeanFactory 容器,只不过在该容器的基础上继续增强了许多功能。
在 ApplicationContext 中,容器的初始化都是从 refresh 方法开始,该方法会调用 obtainFreshBeanFactory 方法去获取一个 ConfigurableListableBeanFactory 类型的容器,问题是 ConfigurableListableBeanFactory 只有一个实现类,那就是 DefaultListableBeanFactory,所以我们说,在 ApplicationContext 中使用的都是 DefaultListableBeanFactory 容器。
因此,在具体实践中,如果能够使用 ApplicationContext,就尽量不要直接使用 DefaultListableBeanFactory 或者其他容器,除非你想完全控制容器的运行。
下面这张表格列出来了 BeanFactory 和 ApplicationContext 之间的一些差别。
特性 | BeanFactory | ApplicationContext |
---|---|---|
Bean 的实例化/注入 | 支持 | 支持 |
Bean 生命周期管理 | 不支持 | 支持 |
自动触发 BeanPostProcessor | 不支持 | 支持 |
自动触发 BeanFactoryPostProcessor | 不支持 | 支持 |
国际化(I18N) | 不支持 | 支持 |
内置 ApplicationEvent 发布机制 | 不支持 | 支持 |
好啦,这样梳理一下,容器应该就好理解很多了,接下来的文章松哥会通过具体的案例,来和小伙伴们演示不同 BeanFactory 以及 ApplicationContext 的用法。