通过 Bean 工厂获取 Bean 的过程
代码仓库 :Gitee 仓库链接
本文档的所有示例代码都可以在代码仓库中找到,建议结合代码一起阅读。
学习思路说明
getBean() 方法的源码逻辑相比之前的 Bean 定义加载过程更加复杂,涉及单例缓存、循环依赖处理、FactoryBean 处理、Bean 生命周期管理等多个环节。为了让大家更好地理解整个流程,本文采用以下学习策略:
- 整体流程先行 :首先从宏观角度总结 Bean 获取的完整流程,帮助大家建立对
getBean()方法执行链路的基本认知。 - 分场景深入:在有了整体印象之后,我们将按照不同的 Bean 配置场景(如单例 Bean、Prototype Bean、FactoryBean、循环依赖等)进行深入的源码阅读和分析。
- 实践验证:对于源码中尚未覆盖到的代码路径,我们会通过配置相应的 Bean 定义和编写测试用例来进行实际调试,确保对每个关键路径都有深入的理解。
通过这种"先整体后局部,先理论后实践"的学习方式,我们可以更系统、更全面地掌握 Spring Bean 获取机制的设计思想和实现细节。
回顾学习历程
在之前的文章中,我们深入探索了 Spring 从 XML 配置文件加载 Bean 定义的全过程。从 XML 配置的校验、解析到 Bean 定义的注册,我们逐步了解了 Spring 框架在 Bean 定义加载阶段的设计思想和实现细节。
现在,Bean 定义已经注册到容器中,接下来我们需要了解:当调用 getBean() 方法时,Spring 是如何根据 Bean 定义创建 Bean 实例的?
本文将深入探索通过 Bean 工厂获取 Bean 的完整过程,包括:
- Bean 获取的整体流程
- 单例 Bean 的获取机制
- Prototype Bean 的获取机制
- FactoryBean 的处理
- 循环依赖的解决
- Bean 的创建过程
Bean 获取的整体流程
入口方法:getBean()
BeanFactory 接口定义了多个 getBean() 方法的重载版本:
java
// 根据名称获取 Bean
Object getBean(String name) throws BeansException;
// 根据名称和类型获取 Bean
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
// 根据类型获取 Bean
<T> T getBean(Class<T> requiredType) throws BeansException;
// 根据名称和参数获取 Bean(用于构造函数注入)
Object getBean(String name, Object... args) throws BeansException;
核心实现:AbstractBeanFactory.getBean()
AbstractBeanFactory 是 BeanFactory 接口的抽象实现,提供了 getBean() 方法的核心逻辑:
java
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
关键发现 :所有的 getBean() 方法最终都调用了 doGetBean() 方法,这是 Bean 获取的核心方法。
doGetBean() 方法的核心流程
doGetBean() 方法是 Bean 获取的核心方法,它包含了 Bean 获取的完整逻辑。让我们逐步分析这个方法:
第一步:转换 Bean 名称
java
final String beanName = transformedBeanName(name);
作用:
- 处理 FactoryBean 的特殊前缀
& - 处理别名,将别名转换为实际的 Bean 名称
示例:
"&myFactoryBean"→"myFactoryBean"(获取 FactoryBean 本身)"myBean"→"realBean"(如果 myBean 是别名,则转换为实际名称)
第二步:尝试从缓存获取单例 Bean
java
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
作用:
- 从单例缓存中获取已存在的 Bean 实例
- 如果找到,直接返回(单例 Bean 只创建一次)
- 如果未找到,继续后续的创建流程
缓存结构:
singletonObjects:存储完全初始化好的单例 BeanearlySingletonObjects:存储提前暴露的单例 Bean(用于解决循环依赖)singletonFactories:存储单例 Bean 的工厂对象
第三步:检查 Bean 定义是否存在
java
BeanDefinition bd = getMergedBeanDefinition(beanName);
作用:
- 获取合并后的 Bean 定义(包括父 Bean 定义的属性)
- 如果 Bean 定义不存在,抛出
NoSuchBeanDefinitionException
第四步:检查依赖的 Bean
java
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(...); // 循环依赖检查
}
registerDependentBean(dep, beanName);
getBean(dep); // 递归获取依赖的 Bean
}
}
作用:
- 检查 Bean 的
depends-on属性 - 如果存在依赖,先递归获取依赖的 Bean
- 检查是否存在循环依赖
第五步:根据作用域创建 Bean
java
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 其他作用域(request、session 等)
String scopeName = mbd.getScope();
Scope scope = this.scopes.get(scopeName);
Object scopedInstance = scope.get(beanName, () -> {
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
关键点:
- 单例 Bean :通过
getSingleton()方法创建,确保只创建一次 - Prototype Bean:每次调用都创建新实例
- 其他作用域 :通过
Scope接口管理
单例 Bean 的获取机制
getSingleton() 方法的三级缓存机制
DefaultSingletonBeanRegistry.getSingleton() 方法实现了单例 Bean 的三级缓存机制:
java
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 第一级缓存:完全初始化好的单例 Bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 第二级缓存:提前暴露的单例 Bean(用于解决循环依赖)
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 第三级缓存:单例 Bean 的工厂对象
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
三级缓存的作用:
-
singletonObjects(一级缓存):
- 存储完全初始化好的单例 Bean
- 这是最终返回给用户的 Bean 实例
-
earlySingletonObjects(二级缓存):
- 存储提前暴露的单例 Bean
- 用于解决循环依赖问题
- 这些 Bean 可能还没有完全初始化
-
singletonFactories(三级缓存):
- 存储单例 Bean 的工厂对象
- 用于创建提前暴露的 Bean 实例
- 创建后会被移到二级缓存
循环依赖的解决机制
问题场景:
- BeanA 依赖 BeanB
- BeanB 依赖 BeanA
解决流程:
-
创建 BeanA:
- 调用构造函数创建 BeanA 实例(此时 BeanA 还未完全初始化)
- 将 BeanA 的工厂对象放入三级缓存
- 开始注入 BeanA 的属性
-
注入 BeanB:
- 发现 BeanA 需要注入 BeanB
- 调用
getBean("beanB")获取 BeanB
-
创建 BeanB:
- 调用构造函数创建 BeanB 实例
- 将 BeanB 的工厂对象放入三级缓存
- 开始注入 BeanB 的属性
-
注入 BeanA:
- 发现 BeanB 需要注入 BeanA
- 调用
getBean("beanA") - 从三级缓存中获取 BeanA 的工厂对象
- 创建 BeanA 的提前暴露实例,放入二级缓存
- 返回给 BeanB 使用
-
完成 BeanB 的初始化:
- BeanB 完成属性注入
- BeanB 从三级缓存移到一级缓存
-
完成 BeanA 的初始化:
- BeanA 完成属性注入
- BeanA 从二级缓存移到一级缓存
关键点:
- 三级缓存机制允许在 Bean 完全初始化之前暴露 Bean 实例
- 只适用于单例 Bean,Prototype Bean 无法使用此机制
- 只适用于通过 setter 注入的循环依赖,构造函数注入的循环依赖无法解决
Prototype Bean 的获取机制
Prototype Bean 的获取相对简单,因为每次都需要创建新实例:
java
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
关键点:
- 每次调用
getBean()都会创建新实例 - 不放入任何缓存
- 如果存在循环依赖,会抛出异常(因为无法提前暴露实例)
FactoryBean 的处理
getObjectForBeanInstance() 方法
在获取 Bean 实例后,需要检查是否是 FactoryBean:
java
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 如果名称以 & 开头,直接返回 FactoryBean 本身
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName);
}
return beanInstance;
}
// 如果不是 FactoryBean,直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
// 如果是 FactoryBean,获取它创建的对象
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
关键逻辑:
- 如果名称以
&开头,返回 FactoryBean 本身 - 如果不是 FactoryBean,直接返回实例
- 如果是 FactoryBean,调用
getObjectFromFactoryBean()获取目标对象
getObjectFromFactoryBean() 方法
java
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, object);
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
关键逻辑:
- 如果 FactoryBean 是单例,将创建的对象缓存到
factoryBeanObjectCache - 如果 FactoryBean 是 Prototype,每次调用都创建新对象
- 调用
factory.getObject()创建目标对象 - 应用后置处理器(如果需要)
Bean 的创建过程:createBean()
createBean() 方法是 Bean 创建的核心方法,它负责根据 Bean 定义创建 Bean 实例:
java
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 解析 Bean 的类
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 2. 准备方法覆盖(lookup-method、replaced-method)
mbd.prepareMethodOverrides();
// 3. 应用 BeanPostProcessor(实例化前)
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
// 4. 创建 Bean 实例
Object beanInstance = doCreateBean(beanName, mbd, args);
return beanInstance;
}
doCreateBean() 方法
doCreateBean() 方法执行实际的 Bean 创建逻辑:
java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 实例化 Bean(调用构造函数)
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
// 2. 应用 MergedBeanDefinitionPostProcessor
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
// 3. 提前暴露 Bean(用于解决循环依赖)
boolean earlySingletonExposure = (mbd.isSingleton() &&
this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 4. 初始化 Bean(属性注入、初始化方法等)
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
// 异常处理
}
// 5. 注册单例 Bean
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
}
}
return exposedObject;
}
关键步骤:
-
createBeanInstance():创建 Bean 实例
- 选择合适的构造函数
- 调用构造函数创建实例
- 返回
BeanWrapper对象
-
populateBean():填充 Bean 属性
- 解析属性值
- 注入依赖的 Bean
- 应用属性后置处理器
-
initializeBean():初始化 Bean
- 调用
BeanPostProcessor.postProcessBeforeInitialization() - 调用初始化方法(
init-method、InitializingBean.afterPropertiesSet()) - 调用
BeanPostProcessor.postProcessAfterInitialization()
- 调用
代码示例
示例 1:单例 Bean 的获取
配置文件 :applicationContext-getbean.xml
xml
<bean id="userService" class="com.example.getbean.UserService">
<property name="name" value="用户服务"/>
</bean>
测试代码:
java
@Test
public void testGetSingletonBean() {
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource("applicationContext-getbean.xml")
);
// 第一次获取
UserService service1 = factory.getBean("userService", UserService.class);
// 第二次获取
UserService service2 = factory.getBean("userService", UserService.class);
// 验证是同一个实例
assertSame(service1, service2);
}
示例 2:Prototype Bean 的获取
配置文件:
xml
<bean id="prototypeBean" class="com.example.getbean.PrototypeBean" scope="prototype">
<property name="name" value="原型Bean"/>
</bean>
测试代码:
java
@Test
public void testGetPrototypeBean() {
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource("applicationContext-getbean.xml")
);
// 第一次获取
PrototypeBean bean1 = factory.getBean("prototypeBean", PrototypeBean.class);
// 第二次获取
PrototypeBean bean2 = factory.getBean("prototypeBean", PrototypeBean.class);
// 验证是不同的实例
assertNotSame(bean1, bean2);
}
示例 3:循环依赖的解决
配置文件:
xml
<bean id="serviceA" class="com.example.getbean.ServiceA">
<property name="serviceB" ref="serviceB"/>
</bean>
<bean id="serviceB" class="com.example.getbean.ServiceB">
<property name="serviceA" ref="serviceA"/>
</bean>
测试代码:
java
@Test
public void testCircularDependency() {
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource("applicationContext-getbean.xml")
);
// 获取 ServiceA,会触发循环依赖的解决
ServiceA serviceA = factory.getBean("serviceA", ServiceA.class);
ServiceB serviceB = factory.getBean("serviceB", ServiceB.class);
// 验证循环依赖已解决
assertNotNull(serviceA.getServiceB());
assertNotNull(serviceB.getServiceA());
assertSame(serviceA, serviceB.getServiceA());
assertSame(serviceB, serviceA.getServiceB());
}
总结
通过本文的学习,我们深入了解了 Spring 通过 Bean 工厂获取 Bean 的完整过程:
核心流程
- Bean 名称转换:处理别名和 FactoryBean 前缀
- 缓存查找:从单例缓存中查找已存在的 Bean
- Bean 定义获取:获取合并后的 Bean 定义
- 依赖处理:递归获取依赖的 Bean
- Bean 创建:根据作用域创建 Bean 实例
- FactoryBean 处理:处理 FactoryBean 的特殊逻辑
关键机制
-
三级缓存机制:
- 一级缓存:完全初始化好的单例 Bean
- 二级缓存:提前暴露的单例 Bean
- 三级缓存:单例 Bean 的工厂对象
-
循环依赖解决:
- 只适用于单例 Bean
- 只适用于 setter 注入
- 通过提前暴露 Bean 实例解决
-
FactoryBean 处理:
- 通过
&前缀获取 FactoryBean 本身 - 通过普通名称获取 FactoryBean 创建的对象
- FactoryBean 创建的对象也会被缓存(如果是单例)
- 通过
学习心得
通过阅读 Spring 源码,我们不仅了解了 Bean 获取的实现细节,更重要的是理解了 Spring 框架的设计思想:
- 延迟加载:Bean 只有在需要时才创建
- 缓存机制:通过多级缓存提高性能
- 循环依赖解决:通过提前暴露实例解决循环依赖
- 扩展性 :通过
BeanPostProcessor等机制支持扩展
这些设计思想不仅适用于 Spring 框架,也可以应用到我们自己的项目中。
参考资料
代码仓库
- Gitee 仓库 :查看完整代码
- 配置文件:
code/spring-basic/src/main/resources/applicationContext-getbean.xml - 测试代码:
code/spring-basic/src/test/java/com/example/getbean/GetBeanProcessTest.java
- 配置文件:
Spring Framework 源码
BeanFactory接口AbstractBeanFactory抽象类DefaultListableBeanFactory实现类DefaultSingletonBeanRegistry单例注册表