一、介紹
從spring容器中獲取單例時有兩種情況:緩存中存在和緩存中不存在。緩存中不存在的情況,需要調用getSingleton()方法來獲取單例。本章主要介紹獲取單例的整體流程,該邏輯中創建bean的步驟較爲複雜,放在後面章節單獨介紹。
二、bean加載流程
- 獲取用戶傳入name對應的beanName
- 嘗試從緩存中獲取bean實例
- 緩存中不存在,加載bean實例
3.1. 檢查循環依賴
3.2 處理parentBeanFactory
3.3 處理依賴的bean(dependsOn)
3.4 三種bean實例的創建
3.4.1 單例bean的創建
3.4.1.1 獲取單例bean,getSingleton()方法(本章解析)
3.4.1.2 創建bean,createBean()方法
3.4.2 原型bean的創建
3.4.3 根據scope策略創建bean - 從bean實例中獲取真正的對象
- 轉換對象類型
- 返回對象實例
三、相關類及方法
- org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean:加載一個Bean的整體過程都在這個方法中
- org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>):獲取單例
- org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton:把單例bean存入緩存
四、源碼分析
1. 先看加載bean的方法,AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 1.轉換beanName,主要處理別名、以&開頭的name
final String beanName = transformedBeanName(name);
Object bean;
// 2.嘗試從單例緩存中獲取bean實例
Object sharedInstance = getSingleton(beanName);
// 3. 獲取bean實例
// 3.1 緩存中已存在bean實例
if (sharedInstance != null && args == null) {
// 省略日誌輸出代碼...
// 從bean實例中獲取對象(本章重點,獲取實例中的對象)
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 緩存中不存在bean實例的情況
else {
// 省略父工廠處理相關代碼...
try {
// 省略dependsOn相關代碼...
// 3.2 創建單例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);
}
// 3.3 創建原型bean實例
else if (mbd.isPrototype()) {
// 省略原型bean創建邏輯...
}
// 3.4 根據scope創建bean實例
else {
// 省略根據scope策略創建bean邏輯...
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 省略其他代碼.
...
}
可以看到緩存中不存在bean實例時,創建單例bean的邏輯是調用getSingleton()方法完成的,跟進去看下具體邏輯。
2. 獲取單例的整體邏輯
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 同步代碼塊
synchronized (this.singletonObjects) {
// 1. 再次嘗試從緩存中獲取bean實例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 2. 創建單例的前置處理,把該beanName置爲創建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 3. 通過入參ObjectFactory創建bean(該方法邏輯較爲複雜,後面章節單獨講述)
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 4. 創建單例的後置處理
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 5. 把創建的單例加入到緩存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
3. 創建單例的前置處理
// 保存正在創建中狀態的beanName
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
把該beanName加入到DefaultSingletonBeanRegistry#singletonsCurrentlyInCreation,表明該bean正在創建中。
4. 把創建好的單例加入到緩存
// 單例對象緩存: bean name --> bean instance
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 按註冊順序排列的bean名稱列表
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 緩存單例對象
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
// 記錄已註冊beanName
this.registeredSingletons.add(beanName);
}
}
5. 創建單例的後置處理
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
把該beanName從DefaultSingletonBeanRegistry#singletonsCurrentlyInCreation中移除,表明該bean已創建完成。
五、總結
- 從源碼分析中看到,容器中已加載的單例bean對象和已註冊的beanName保存在DefaultSingletonBeanRegistry類中
// bean對象緩存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 已註冊beanName
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
- 獲取單例邏輯可以總結爲以下五個步驟
- 再次嘗試從緩存中獲取bean實例
- 創建單例的前置處理
- 通過入參ObjectFactory創建bean
- 創建單例的後置處理
- 把創建的單例加入到緩存
後面我們就單獨講下第3個步驟:通過入參ObjectFactory創建bean