Spring 核心技术解析【纯干货版】- II:Spring 基础模块 Spring-Beans 模块精讲
在现代软件开发中,依赖注入和控制反转已经成为了架构设计中不可或缺的模式。而 Spring 框架,作为 Java 领域最流行的开发框架之一,提供了一整套强大而灵活的机制来实现这些模式。Spring-Beans 模块是 Spring 框架中最基础和核心的模块之一,负责管理应用程序中的 Bean(即对象)的生命周期和依赖关系。
本篇文章将深入解析 Spring-Beans 模块的核心概念和功能,帮助开发者全面理解 Spring 框架中的 Bean 定义、管理和生命周期管理等关键机制。通过详细的代码示例,我们将探索如何通过 Spring-Beans 来实现高效的依赖注入,如何管理 Bean 的生命周期,以及如何解析 XML 配置文件等重要技术细节。
文章目录
- 1、Spring-Beans 模块概述
- 1.1、Spring-Beans 模块介绍
- 1.2、Spring-Beans 模块作用
- 2、Spring-Beans 提供的对 Bean 的定义和管理
- 2.1、BeanDefinition
- 2.2、BeanFactory
- 3、Spring-Beans 提供的生命周期管理方式
- 3.1、doCreateBean 方法
- 3.2、实例化 Bean
- 3.3、属性注入
- 3.4、初始化 Bean
- 3.5、代理处理
- 4、Spring-Beans 提供的解析 XML 配置文件的方式
- X、后记
1、Spring-Beans 模块概述
1.1、Spring-Beans 模块介绍
Spring-Beans 模块,是 Spring 核心容器模块之一。它主要负责 Bean(即应用程序中的对象)的定义、配置、创建、管理和销毁。Spring Beans 模块通过依赖注入(Dependency Injection, DI)和控制反转(Inversion of Control, IoC)模式帮助开发者解耦对象之间的依赖关系,从而简化代码结构,提高可测试性和可维护性。
Spring-Beans 的核心实体是 BeanDefinition
和 BeanFactory
。前者映射我们的定义,后者则是依据定义生产 bean 的工厂。
1.2、Spring-Beans 模块作用
在作者看来 Spring-Beans 模块主要提供的功能大致可以分为 3 块:
- 提供对 Bean 的定义和管理:Spring-Beans 提供了
BeanDefinition
来描述 Bean,用BeanFactory
来管理 Bean。 - 提供对 Bean 生命周期的管理方式:Spring-Beans 在
AbstractAutowireCapableBeanFactory
类中使用doCreateBean
方法创建 Bean,其过程就是最基本的 Bean 的生命周期。 - 提供解析 XML 配置文件的方式:Spring-Beans 模块提供了可以将 Bean 从 XML 配置中进行解析出来的方式,
2、Spring-Beans 提供的对 Bean 的定义和管理
2.1、BeanDefinition
在上一篇关于 Spring-Core 的模块解析文章中,提到了 Spring-Core 实现了将 Class
文件转换为抽象 Resource
,并使用 ASM 获取 Class
元数据的方式。而在 Spring-Beans 中,则进一步解析元数据,提取 Bean 的定义信息,并封装到 BeanDefinition
中。
换句话说,Spring 容器管理一个 Bean 或多个 Bean,这些 Bean 是通过我们提供给容器的配置元数据被创建出来,在容器中,这些 Bean 的定义用 BeanDefinition
对象来表示(BeanDefinition
就是用来描述一个 Bean 或者 BeanDefinition
就是 Bean 的定义)。
BeanDefinition
通常包含以下元数据:
- 全限定类名, 通常是 Bean 的实际实现类;
- Bean 行为配置元素,它们说明 Bean 在容器中的行为(作用域、生命周期回调等等);
- Bean 执行工作所需要的的其他 Bean 的引用,这些 Bean 也称为协作者或依赖项;
- 其他配置信息,例如,管理连接池的 Bean 中,限制池的大小或者使用的连接的数量。
2.2、BeanFactory
有了对 Bean 的定义,自然还需要有对 Bean 的管理。而 BeanFactory
就是一个为存储和管理 Spring Bean 提供基本功能的 IOC 容器。
从具体实现来说,BeanFactory
接口是整个模块的核心接口,几乎所有功能都是围绕对象展开的。BeanFactory
提供了创建对象的功能,并对一部分对象进行管理,这是控制反转的基础。此外,在创建对象的过程中完成依赖注入,这时我们可以说 BeanFactory
是一个典型的 IOC 容器,它提供了基本的 IoC(控制反转)功能,是所有 Spring 应用的基石。
使用的简单示例:
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
public class BeanFactoryExample {
public static void main(String[] args) {
// 创建一个 BeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 创建 BeanDefinition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
// 设置 Bean 的类型
beanDefinition.setBeanClass(MyBean.class);
// 注册 BeanDefinition 到工厂
factory.registerBeanDefinition("myBean", beanDefinition);
// 获取 Bean 实例
MyBean myBean = (MyBean) factory.getBean("myBean");
// 使用 Bean
// 输出: Hello, Default Message
myBean.sayHello();
// 修改属性值
myBean.setMessage("Spring Bean Factory");
// 输出: Hello, Spring Bean Factory
myBean.sayHello();
}
static class MyBean {
private String message;
public MyBean() {
this.message = "Default Message";
}
public void setMessage(String message) {
this.message = message;
}
public void sayHello() {
System.out.println("Hello, " + message);
}
}
}
3、Spring-Beans 提供的生命周期管理方式
我们都知道 Spring Bean 具有生命周期,而这生命周期的能力就是在 Spring-Beans 模块这里提供的。 Spring-Beans 模块提供了一个名为 AbstractAutowireCapableBeanFactory
的抽象类。
AbstractAutowireCapableBeanFactory
是 Spring 框架中至关重要的核心类之一,承担着整个 Bean 生命周期关键步骤的管理责任。其在 Bean 实例化、属性注入、初始化及代理处理等关键环节中发挥着关键作用,贯穿了整个 Bean 的声明周期。
3.1、doCreateBean 方法
如果深入研究 AbstractAutowireCapableBeanFactory
源码,将关注其中一个核心方法:doCreateBean
。这个方法是贯穿 Bean 生命周期的纽带,涵盖了实例化、属性注入、初始化以及代理处理等关键任务。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// 尝试从缓存中移除已创建的单例实例,如果是单例 Bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
// 如果缓存中没有实例化的 Bean,则调用 createBeanInstance 创建新的实例
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
// 获取实例化后的 Bean 对象和类型
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
// 如果 Bean 类型不为 NullBean,则记录解析后的目标类型
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 同步操作,确保在处理过程中 BeanDefinition 只有一个线程在操作
synchronized(mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 应用 BeanDefinition 的后处理器(例如 @Configuration 注解的类的处理)
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable var17) {
// 如果后处理失败,抛出 BeanCreationException
Throwable ex = var17;
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex);
}
// 标记 BeanDefinition 已经处理过了
mbd.postProcessed = true;
}
}
// 如果是单例 Bean 并且容器允许循环引用,则尝试提前缓存 Bean 实例,解决循环依赖
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
// 提前将 Bean 工厂放入缓存中,防止循环引用时直接获取到未完全初始化的实例
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
Object exposedObject = bean;
try {
// 完成依赖注入(填充 Bean 的属性)
this.populateBean(beanName, mbd, instanceWrapper);
// 完成 Bean 的初始化操作(例如调用 @PostConstruct 标注的方法)
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
// 如果初始化过程中出现异常,抛出 BeanCreationException
Throwable ex = var18;
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException)ex).getBeanName())) {
throw (BeanCreationException)ex;
}
// 如果初始化失败,抛出异常
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
// 如果提前暴露了单例对象,需要检查是否是早期的引用
if (earlySingletonExposure) {
// 尝试获取早期引用
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果实际对象还是原始对象,则用早期引用替代
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
// 如果有依赖的 Bean 还在等待注入,检测并抛出循环依赖异常
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// 如果依赖 Bean 未被创建,则加入集合
if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 如果依赖集合不为空,抛出循环依赖异常
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean.");
}
}
}
}
try {
// 注册 Bean 的销毁方法(例如 DisposableBean 或 @PreDestroy 标注的方法)
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject; // 返回最终暴露的 Bean 实例
} catch (BeanDefinitionValidationException var16) {
// 如果销毁方法签名无效,抛出异常
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
3.2、实例化 Bean
在这一步中,doCreateBean 方法首先尝试从单例缓存中获取 Bean 的包装实例,以支持单例模式。如果未找到,它将通过 createBeanInstance 方法进行实例化。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// 尝试从缓存中移除已创建的单例实例,如果是单例 Bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
// 如果缓存中没有实例化的 Bean,则调用 createBeanInstance 创建新的实例
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
...
}
3.3、属性注入
populateBean 方法负责将属性注入到 Bean 实例中,包括将依赖项注入到 Bean 中,以建立 Bean 之间的关系。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
...
// 完成依赖注入(填充 Bean 的属性)
this.populateBean(beanName, mbd, instanceWrapper);
...
}
3.4、初始化 Bean
在初始化 Bean 这一步,initializeBean 方法被调用,负责执行 Bean 的初始化。这包括调用任何与 Bean 生命周期相关的回调方法,以及应用任何与 Bean 相关的后处理器。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
...
// 完成 Bean 的初始化操作(例如调用 @PostConstruct 标注的方法)
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
...
}
3.5、代理处理
在初始化之后,如果存在代理,通过从二级缓存获取早期半成品对象,实现代理的替换。这对于 AOP 等方面的处理非常关键。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
...
// 如果提前暴露了单例对象,需要检查是否是早期的引用
if (earlySingletonExposure) {
// 尝试获取早期引用
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果实际对象还是原始对象,则用早期引用替代
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
...
}
...
}
...
}
4、Spring-Beans 提供的解析 XML 配置文件的方式
在 Spring 中,XML 文件 主要用于配置 Bean 定义,这些文件会被 Spring 读取并解析,然后根据这些解析出的元数据来管理 Bean。这一功能的实现就是在 Spring-Beans 模块中完成的。
整个过程实际上分为两个部分:
- 读取 XML 配置文件(通过文件系统、类路径等方式读取 XML 文件)。
- 解析 XML 内容(使用 XML 解析器将 XML 内容转换为 Java 对象,如
BeanDefinition
)并将其加载到 Spring 容器中。
Spring-Beans 模块提供了解析 XML 内容并将其加载到 Spring 容器中的方式。XmlBeanDefinitionReader
是 Spring 用于读取 XML 配置文件并解析 Bean 定义的核心类,它继承自 AbstractBeanDefinitionReader
类,并实现了 BeanDefinitionReader
接口。
XmlBeanDefinitionReader
主要职责:
- 解析 XML 文件:通过 XML 解析机制(基于 DOM 或 SAX)读取 XML 配置文件。
- 将 XML 转换为
BeanDefinition
:它负责将 XML 配置文件中的信息转换为BeanDefinition
对象,这些对象用于描述 Bean 的元数据。 - 注册
BeanDefinition
:一旦解析完成,它会将这些BeanDefinition
注册到 Spring 容器的BeanFactory
(通常是DefaultListableBeanFactory
)中。
使用示例:
准备 XML 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定义一个名为 car 的 Bean -->
<bean id="car" class="com.example.Car">
<property name="model" value="Tesla Model S"/>
<property name="year" value="2023"/>
</bean>
</beans>
创建 Bean 类:假设我们有一个 Car
类,它包含 model
和 year
两个属性,并且有相应的 getter 和 setter 方法:
package com.example;
public class Car {
private String model;
private int year;
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "Car{model='" + model + "', year=" + year + "}";
}
}
使用 XmlBeanDefinitionReader
加载 XML 配置:XmlBeanDefinitionReader
负责读取并解析 XML 文件,将其中的 Bean 定义转换为 BeanDefinition
对象,并将它们注册到 Spring 容器中。
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.factory.BeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class Main {
public static void main(String[] args) {
// 创建一个 BeanFactory 实例
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建一个 XmlBeanDefinitionReader 实例
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// 通过 ClassPathResource 加载 XML 配置文件
Resource resource = new ClassPathResource("beans.xml");
// 加载并解析 XML 配置文件
int beanCount = reader.loadBeanDefinitions(resource);
System.out.println("Total Beans loaded: " + beanCount);
// 获取并使用注册的 Bean
Car car = (Car) beanFactory.getBean("car");
System.out.println(car);
}
}
X、后记
通过本篇文章的讲解,相信大家对于 Spring-Beans 模块的核心概念有了更深刻的理解。Spring-Beans 的依赖注入和生命周期管理为我们的应用提供了更高的可维护性、可扩展性和可测试性。在实际开发过程中,掌握 Spring-Beans 的核心技术,不仅能够帮助我们更好地构建应用,还能提高代码的解耦度和开发效率。
Spring-Beans 模块的功能强大而灵活,但也需要开发者通过不断的实践来深入掌握。希望本篇文章能为大家在使用 Spring 框架时提供一些帮助,也欢迎大家持续关注 Spring 框架的最新动态和最佳实践,共同进步。