Spring源码分析三:bean的加载 - doGetBean概述
前言
在Spring框架中,bean的加载过程是核心中的核心,而doGetBean()方法则是这一过程的入口和关键所在。本文将深入解析AbstractBeanFactory类中的doGetBean()方法,从源码层面剖析Spring容器加载bean的完整流程,包括bean的获取、创建、初始化以及各种特殊情况的处理机制。
一、bean加载的整体流程
在Spring容器中,bean的加载主要经历以下几个阶段:
- 转换bean名称:处理别名、解析FactoryBean的前缀等
- 尝试从缓存获取单例:解决循环依赖的关键步骤
- 检查父容器:如果当前容器没有找到,尝试从父容器查找
- 处理依赖初始化:确保依赖的bean先被初始化
- 创建bean实例:根据不同作用域创建bean实例
- 类型转换:如果需要,将bean转换为所需类型
二、doGetBean方法概述
doGetBean()方法是AbstractBeanFactory中的核心方法,其基本结构如下:
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 1. 转换bean名称(处理别名、FactoryBean等)
String beanName = transformedBeanName(name);
// 2. 尝试从缓存获取单例
Object bean;
Object sharedInstance = getSingleton(beanName);
// 3. 处理获取到的实例
if (sharedInstance != null && args == null) {
// 处理FactoryBean的特殊情况
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 4. 检查prototype作用域的循环依赖
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 5. 检查父容器
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 在父容器中查找
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 6. 获取合并的BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 7. 检查depends-on依赖
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 处理依赖关系
}
}
// 8. 根据作用域创建bean
if (mbd.isSingleton()) {
// 创建单例bean
}
else if (mbd.isPrototype()) {
// 创建prototype bean
}
else {
// 处理其他自定义作用域
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 9. 类型转换
return adaptBeanInstance(name, bean, requiredType);
}
三、源码深度解析
1. 转换bean名称
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
// BeanFactoryUtils.transformedBeanName
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
// SimpleAliasRegistry.canonicalName
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
名称转换主要处理两种情况:
- FactoryBean的名称前缀(&)
- bean的别名
2. 尝试从缓存获取单例
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存:完全初始化好的单例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 二级缓存:早期引用,已实例化但未初始化的单例
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 三级缓存:单例工厂
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
三级缓存解决循环依赖:
- singletonObjects:完全初始化好的单例
- earlySingletonObjects:早期引用,已实例化但未初始化
- singletonFactories:单例工厂,用于创建早期引用
3. 处理FactoryBean
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 如果不是FactoryBean或者想要FactoryBean本身,直接返回
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// 如果不是FactoryBean,直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
// 处理FactoryBean创建的对象
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
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;
}
4. 检查prototype作用域的循环依赖
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object cur = this.prototypesCurrentlyInCreation.get();
return (cur != null &&
(cur.equals(beanName) || (cur instanceof Set && ((Set<?>) cur).contains(beanName))));
}
Spring不支持prototype作用域的循环依赖,会直接抛出异常。
5. 检查父容器
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
6. 获取合并的BeanDefinition
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
// 检查缓存
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
if (bd.getParentName() == null) {
// 没有父定义,直接克隆
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// 有父定义,需要合并
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
// 处理自引用情况
}
// 创建合并后的定义
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
}
// 设置作用域
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// 缓存合并后的定义
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
7. 处理depends-on依赖
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
8. 根据作用域创建bean
单例作用域
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
getSingleton()方法实现了单例创建的逻辑:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 创建前的检查
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
// 调用createBean方法创建单例
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
finally {
if (!newSingleton) {
afterSingletonCreation(beanName);
}
}
if (newSingleton) {
// 添加到单例缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
prototype作用域
else if (mbd.isPrototype()) {
Object prototypeInstance;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
其他自定义作用域
else {
String scopeName = mbd.getScope();
Scope scope = this.scopes.get(scopeName);
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread", ex);
}
}
9. 类型转换
protected <T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return (T) convertedBean;
}
catch (TypeMismatchException ex) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
四、设计模式分析
1. 模板方法模式
doGetBean()方法定义了bean加载的骨架,具体创建过程由createBean()等子方法实现。
2. 工厂模式
通过ObjectFactory接口实现bean创建的延迟和回调机制。
3. 单例模式
单例bean的缓存和管理体现了单例模式的应用。
4. 装饰器模式
FactoryBean的使用体现了装饰器模式的思想。
五、性能考虑与优化
1. 缓存机制
三级缓存的设计极大地提高了单例bean的获取效率。
2. 并发控制
通过synchronized关键字和ConcurrentHashMap确保线程安全。
3. 延迟加载
ObjectFactory的使用实现了bean创建的延迟加载。
六、常见问题与解决方案
1. 循环依赖问题
问题:如何解决bean之间的循环依赖?
解决方案:
- 通过三级缓存机制解决单例bean的循环依赖
- 不支持prototype作用域的循环依赖
2. 作用域不匹配
问题:如何确保获取的bean符合预期的作用域?
解决方案:
- 通过isPrototypeCurrentlyInCreation()等方法检查作用域状态
- 在创建前和创建后执行相应的作用域处理逻辑
3. 类型转换异常
问题:如何正确处理bean的类型转换?
解决方案:
- 使用TypeConverter进行安全的类型转换
- 提供详细的异常信息帮助定位问题
七、总结
doGetBean()方法是Spring容器加载bean的核心入口,它实现了bean加载的完整流程,包括:
- bean名称的转换和处理
- 单例bean的缓存机制
- FactoryBean的特殊处理
- 循环依赖的检测和解决
- 不同作用域的创建策略
- 类型转换和安全检查
理解doGetBean()方法的工作原理对于深入掌握Spring容器的bean生命周期管理至关重要,也是解决各种bean加载问题的关键。在后续的文章中,我们将继续深入分析createBean()等方法的实现细节,进一步揭示Spring容器的工作机制。