前情回顧前文「Spring 如何從 IoC 容器中獲取對象?」從整體上分析了如何從 Spring IoC 容器獲取一個 bean 對象。該邏輯由 AbstractBeanFactory#doGetBean 方法實現,主要流程如下:

本文進一步深入細節,主要分析如何創建 singleton(單例)類型的對象。
如何創建單例對象?
從流程圖可以看出,當獲取一個 bean 對象時,Spring 會首先嘗試從緩存中獲取單例對象。
值得注意是的:
- 只有對象是單例的場景,即 scope 為 singleton 時才會緩存對象。
- 這里其實涉及到了所謂的「三級緩存」,為了更容易理解三級緩存,本文先研究這個 bean 對象是什么時候放入緩存的,后面再研究三級緩存。
既然能取,必然有地方把 bean 對象存入了緩存,那緩存中的數據是從哪里來的呢?
下面主要分析單例對象是如何創建、并放入緩存中的。
該邏輯在 AbstractBeanFactory#doGetBean 方法中,主要代碼如下(保留了創建單例 bean 對象的代碼,其他部分暫時忽略):
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
// ...
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// 從緩存中獲取單例 bean 對象
Object sharedInstance = getSingleton(beanName);
// 緩存中不存在 bean 對象
else {
// ...
try {
// 獲取 BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 獲取依賴的 bean 對象
// 若創建一個 bean 對象時依賴其他對象,則先創建被依賴對象
// ...
// 創建 scope 為 singleton(單例)的對象
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ...
}
});
// 處理 FactoryBean 的場景
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 創建 scope 為 prototype 的對象
else if (mbd.isPrototype()) {
// ...
}
// 創建其他類型對象
else {
// ...
}
}
catch (BeansException ex) {
// ...
}
}
// 類型檢查
return (T) bean;
}
}
其實就是這個 DefaultSingletonBeanRegistry#getSingleton 方法,代碼如下:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 單例 bean 對象緩存(beanName, bean)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 先從緩存中獲取 bean 對象
Object singletonObject = this.singletonObjects.get(beanName);
// 緩存中不存在時再去創建
if (singletonObject == null) {
// ...
// 創建單例對象前
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 創建單例對象
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
// catch ...
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 創建單例對象后
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 將對象添加到緩存
addSingleton(beanName, singletonObject);
}
}
// 緩存中有的話直接返回
return singletonObject;
}
}
}
getSingleton 方法會先從緩存 singletonObjects(其實就是一個 Map)中獲取 bean 對象,如果緩存有就直接返回,否則再去創建。創建成功后,會把該對象存入緩存。
創建的邏輯在哪呢?
看代碼是通過 ObjectFactory#getObject 方法來創建的,ObjectFactory 是一個函數式接口:
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
這個方法的實現是什么呢?退回上一層,即 getBean 方法,看這里:
sharedInstance = getSingleton(beanName, () -> {
try {
// 創建 bean 對象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ...
}
});
這里用到了 Lambda 表達式,將如下表達式作為參數:
() -> {
try {
// 創建 bean 對象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ...
}
}
創建 bean 對象的邏輯就在這個 createBean 方法中,它在 AbstractAutowireCapableBeanFactory 類中:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
// catch ...
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 這里可能返回代理對象
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
// catch ...
try {
// 創建 bean 對象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
// catch ...
}
}
- 值得注意的是,resolveBeforeInstantiation 方法其實是跟 AOP 實現相關的,可能在這里生成代理對象就返回了。由于現在主要分析 IoC 的流程,因此這里暫時略過,有興趣的朋友們可以自行研究。
這里繼續沿著主線邏輯走。
創建 bean 對象是在 doCreateBean 方法中實現的,如下:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// 1. 實例化 bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
// catch ...
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 2. 填充屬性
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// catch ...
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// ...
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
// catch ...
return exposedObject;
}
}
- 注意:Instantiate 和 Initialize 雖然看起來有點像,但它倆不是一回事,前者是“實例化”,后者是“初始化”。
這個方法看起來有點長,但最主要的事情只有三件:
- 創建 bean 對象:createBeanInstance 方法
- 填充屬性:populateBean 方法
- 初始化 bean:initializeBean 方法
這幾個方法內部其實都有一大堆堆堆堆堆……的代碼,再對照一下前面給出的整體流程圖 :
就是這樣。
本文在前文整體分析的基礎上又進一步細化,先到這里吧,后面再繼續分析~
小結
如何從 Spring IoC 容器中獲取 bean 對象?前文對此進行了整體流程的分析。
本文在前文的基礎上又進一步細化,主要從整體上探討了 Spring 如何創建單例的 bean 對象,整體上分為三個步驟:
- 創建 bean 對象。
- 填充 bean 屬性
- 初始化 bean 對象
至于這三個步驟具體又做了什么,且聽下回分解。
原文地址:https://mp.weixin.qq.com/s/8YxzDPTAHm5RagI8mX1L7Q