思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。
作者:毅航😜
在上一篇详解Spring中IOC容器的顶层接口中,并对Spring
中常见的IOC
容器进行了介绍分析。简单来看,BeanFactory
作为Spring
容器的顶层父类接口,其主要定义了IOC
容器对于Bean
实例存取的一些公共方法。在此基础上Spring
还扩展出了支持Bean
枚举的ListableBeanFactory
接口、实现容器间继承关系的HierarchicalBeanFactory
接口,以及自动装配的基石的AutowireCapableBeanFactory
接口。
但如果要实现IOC
的特性,仅仅依靠这几个接口是远远不够的,今天我们便继续来扒一扒
与单例Bean
实例相关的SingletonBeanRegistry
接口。
前言
众所周知,BeanFactory
作为IOC
容器的顶层接口,负责管理Spring
容器中的所有Bean
的创建、配置和管理,并定义了获取Bean
、检查Bean
存在性、获取Bean
类型等容器的基本操作。而Spring
为了更好的管理单利Bean
实例,其内部将单例Bean
的管理功能抽象到SingletonBeanRegistry
接口中,从而使得单例Bean
的管理与其他Bean
管理功能解耦。
单例Bean
的管理------SingletonBeanRegistry
在Spring
的中,SingletonBeanRegistry
的主要用于管理单例Bean
的注册和获取 ,同时提供将单例Bean
实例注册到注册表中的方法。其内部构造如下:
java
public interface SingletonBeanRegistry {
void registerSingleton(String beanName, Object singletonObject);
@Nullable
Object getSingleton(String beanName);
boolean containsSingleton(String beanName);
String[] getSingletonNames();
}
其中registerSingleton
的作用是将一个单例Bean
实例注册到注册表中,通过该方式开发人员可以手动向Spring
的容器中添加单例Bean
实例,而无需要通过Spring
的配置文件或注解来定义这些Bean
。getSingleton
方法则是一种的根据Bean
名称获取已经注册的单例Bean
实例的方法。
进一步,containsSingleton
方法对外提供了检查指定名称的单例Bean
是否已经注册的功能,而getSingletonNames
则是允许开发者获取容器中所有单例Bean
的名称。
不难发现,SingletonBeanRegistry
所暴露的一些方法主要完成的工作主要为单例Bean
的获取和注册。看到这你可能会觉得SingletonBeanRegistry
和BeanFactory
功能很类似,但其实两者还是存在一定差异性。
具体来看,BeanFactory
是Spring
的核心接口之一,其主要负责管理Spring
容器中的所有Bean
的创建、配置和管理。 并提供了一种高级的配置机制来管理Bean
以支持不同类型的Bean
的管理。
而SingletonBeanRegistry
则是一个专门用于管理单例Bean
的接口,主要提供了注册、获取和管理单例Bean
的方法 。事实上,SingletonBeanRegistry
并不负责创建Bean
,它的作用是维护已经创建好的单例Bean
实例。
总的来看,SingletonBeanRegistry
专注于单例Bean
的注册和管理,而BeanFactory
负责整个Spring
容器中所有Bean
的创建、配置和管理。 这样的设计使得每个类的职责更加单一。每个接口只承担一种责任。这样划分方式使代码更简洁、更易维护,并且更容易理解和扩展。
与此同时,将单例Bean
的管理功能抽象到SingletonBeanRegistry
接口中,使得单例Bean
的管理与其他Bean
管理功能解耦。这样,如果需要在不同的上下文中管理单例Bean
,可以直接使用SingletonBeanRegistry
接口,而不必依赖于整个BeanFactory
接口。
例如,ConfigurableBeanFactory
接口继承了SingletonBeanRegistry
接口与BeanFactory
。这意味着ConfigurableBeanFactory
的实现类既具有完整的Bean
管理功能,又具备单例Bean
的管理功能。 这样的设计使得Spring
框架将单例Bean
管理功能与其他Bean
管理功能解耦,进而实现了模块间高内聚低耦合的设计。
进一步,你可能会想既然Spring
内部有对于单例Bean
的管理接口,对于多例Bean
是如何进行管理的呢? 要想解答这一问题,我们首先要明白Spring
内部对于Bean
作用域的划分。
在Spring
中的Bean
是存在单例
和多例
之分。具体来看,所谓的单例
即在整个Bean
的生命周期内,该Bean
实例是唯一的。反之,如果Bean
每次请求时都会创建一个新的实例,且Bean
实例不会在容器中进行缓存,则该Bean
的作用范围即为多例
。
如果一个Bean
的作用范围为多例
, 那么该多例Bean
本身并不需要在Spring
容器中全局共享和缓存,因此多例Bean
的生命周期管理相对简单,其大致可以分为如下三个阶段:
- 创建并初始化 :当每次有请求到达
Spring
时,如果有对该Bean
的需要,则每次创建一个新的Bean
实例,然后再执行依赖注入和相关初始化方法。 - 使用:客户端使用Bean实例。
- 销毁:使用完毕后,实例会被垃圾回收机制自动回收。
(注:Spring
容器不负责管理多例Bean
的销毁(除非显式调用销毁方法)。)
为了更深入理解多例Bean
,我们通过一个简单的代码来展示对于多例Bean
的定义和获取过程。
java
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
public class PrototypeBeanExample {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
PrototypeBean bean1 = context.getBean(PrototypeBean.class);
PrototypeBean bean2 = context.getBean(PrototypeBean.class);
System.out.println(bean1 == bean2); // 输出: false
context.close();
}
}
@Configuration
class AppConfig {
@Bean
@Scope("prototype")
public MyPrototypeBean PrototypeBean() {
return new PrototypeBean();
}
}
class PrototypeBean {
}
在上述代码中,我们定义了PrototypeBean
这一对象,同时将其注入到Spring
容器中,并指定Scope
的类型为prototype
。然后,我们通过context.getBean
来分别获取容器中的PrototypeBean
对象,并比较两对象是否相等。
事实上,每次调用context.getBean(MyPrototypeBean.class)
都会创建一个新的PrototypeBean
实例,因此bean1
和bean2
是不同的实例。
总结
本文深入探讨了Spring
框架中SingletonBeanRegistry
接口的作用和管理机制。其作为专门用于管理单例Bean
的接口SingletonBeanRegistry
提供了注册、获取和检查单例Bean
的方法,使单例Bean
的管理与其他Bean
的管理功能解耦。进一步,SingletonBeanRegistry
接口的引入,使得在Spring
内部将单例Bean
的管理功能抽象到SingletonBeanRegistry
接口中,这让单例Bean
的管理与其他Bean
管理功能解耦。如果需要在不同的上下文中管理单例Bean
,可以直接使用SingletonBeanRegistry
接口,而不必依赖于整个BeanFactory
接口。例如,一些轻量级的容器或模块可能只需要单例Bean
管理功能,而不需要完整的Bean
工厂功能,此时完全可以通过实现SingletonBeanRegistry
接口来完成。
本文还解释了多例Bean
的生命周期管理,展示了如何通过代码定义和获取多例Bean
。