spring源码分析四 bean的加载第一步

本文深入剖析了Spring框架中Bean的加载过程,详细解读了AbstractBeanFactory的doGetBean方法,包括如何处理别名、缓存查找、解决循环依赖及FactoryBean的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分析:org.springframework.beans.factory.support.AbstractBeanFactory中
doGetBean的方法:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException 

从缓存中获取bean的代码块如下:
在这里插入图片描述

1. transformedBeanName(name)

final String beanName = transformedBeanName(name);

transformedBeanName方法如下:

protected String transformedBeanName(String name) {
	return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

BeanFactoryUtils.transformedBeanName(name) 方法如下:

public static String transformedBeanName(String name) {
	Assert.notNull(name, "'name' must not be null");
	-- 如果 name 不是以 & 开头的  直接返回
	if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
		return name;
	}
	-- 如果 name 是以 & 开头的,截取掉&,再返回
	return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
		do {
			beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
		}
		while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
		return beanName;
	});
}

public String canonicalName(String name) 代码如下:

	public String canonicalName(String name) {
		String canonicalName = name;
		// Handle aliasing...
		String resolvedName;
		do {
			-- aliasMap 缓存的是 别名的 集合
			-- 这里将传递的别名转换为 真正的名字 
			-- 如果没有别名,则直接返回
			resolvedName = this.aliasMap.get(canonicalName);
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}

综上:final String beanName = transformedBeanName(name); 的功能是先截取掉&(如果有的话),并通过别名(如果传递的参数为别名)找到真正的名字。

接下来:从缓存获取bean:重点

代码如下: Object sharedInstance = getSingleton(beanName);追踪进去,发现再 DefaultSingletonBeanRegistry.java 类中有:

@Override
@Nullable
public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}

再次追踪进去:

// 
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;
}

1. 该方法的作用是:返回给定名字的已经注册过的原始的单例实例

2. singletonObjects是个map, 缓存的是的 单例的名字->单例对象,Object singletonObject = this.singletonObjects.get(beanName); 是从缓存中获取单例。

3. 如果缓存中没有对象,并且该beanName是要当前要创建的单例的名字,
isSingletonCurrentlyInCreation(beanName) 解释见下面

/**
 * Return whether the specified singleton bean is currently in creation
 * (within the entire factory).
 * @param beanName the name of the bean
 */
public boolean isSingletonCurrentlyInCreation(String beanName) {
	return this.singletonsCurrentlyInCreation.contains(beanName);
}

这里:singletonsCurrentlyInCreation 缓存的当前要创建的Bean的所有的名字

/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
		Collections.newSetFromMap(new ConcurrentHashMap<>(16));

4. synchronized (this.singletonObjects) 锁定全局变量,防止并发问题出现

5. singletonObject = this.earlySingletonObjects.get(beanName); earlySingletonObjects 缓存的早期的单例对象,(beanName -> bean)

	/** Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

为什么会有这个判断:如果这个Bean正在加载,则不处理
7. if (singletonObject == null && allowEarlyReference) 如果当前的bean不是正在加载,并且 允许早期的引用创建 (allowEarlyReference whether early references should be created or not,allowEarlyReference的作用:是否应该创建早期的引用 early references)这里为true,为了解决循环依赖的问题

8. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);singletonFactories 缓存的是单例工厂,(beanName -> ObjectFactory)代码如下。 当某些地方需要提前初始化的时候则会调用 addBeanFactory方法将对应的ObjectFactory初始化策略存储再singletonFactories 中

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

9. 如果单例工厂不为空,从工厂获取对象,再将获取到的对象缓存到earlySingletonObjects中,再将单例工厂移除singletonFactories。

if (singletonFactory != null) {
	    singletonObject = singletonFactory.getObject();
		this.earlySingletonObjects.put(beanName, singletonObject);
		this.singletonFactories.remove(beanName);
}

回到文章最开始doGetBean的方法:

代码先贴出来:

	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

如果缓存中获取到了对象,并且没有参数:那么执行
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
为什么有这行代码:getObjectForBeanInstance使用的频率很高,无论是从缓存中加载bean还是根据不同的scope策略加载bean。总之,我们得到bean的实例后要做的第一件事情就是调用这个方法来检测一下正确性,其实就是检测当前bean是否是FactoryBean类型的Bean,如果是,那么需要调用该bean对应的FactoryBean的getObject()的方法作为返回值。

无论是从缓存中加载bean还是根据不同的scope策略加载bean,都只是最原始的bean状态,并不一定是我们想要的Bean。例如:我们都对需要对工厂bean进行处理,那么这里得到的其实是工程bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中的返回的bean,而getObjectForBeanInstance方法就是完成这个工作。

接下来分析这行代码:
在这里插入图片描述

通过方法的描述我们知道:该方法可能返回bean本身,也可能返回bean对应的FactoryBean,具体看源码分析:
在这里插入图片描述

下面我们看上图的最后一个方法:
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
在这里插入图片描述
方法的描述是:从暴露出来的指定的FactoryBean中获取对象
源码分析如下图:
在这里插入图片描述

分析doGetObjectFromFactoryBean方法:这个逻辑比较简单。
在这里插入图片描述
再次分析 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) 这个方法:
spring再获取到object对象之后,并没有直接返回,而是做了后续处理,调用了 object = postProcessObjectFromFactoryBean(object, beanName); 方法,代码如下:
在这里插入图片描述
分析源码如下:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.java

@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
	return applyBeanPostProcessorsAfterInitialization(object, beanName);
}

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessAfterInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

我们发现,这里是对获取到的object对象坐的后续处理。实际调用的postProcessAfterInitialization方法,在实际开发中可以针对此特性设计自己的业务逻辑。

到这里把bean加载的第一步完成了。

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值