單例在Spring的同一個容器中只會被創建一次,后續再獲取bean,就直接從單例緩存中獲取了。
先嘗試從SingletonObjects緩存中加載實例;如果不成功則嘗試從earlySingletonObjects中加載已經在創建完成之前提前暴露的單例Bean;如果失敗了,則從singletonFactories中獲取beanName對應的ObjectFactory,然后在調用ObjectFactory#getObject()方法創建對應的Bean,并放到earlySingletonObjects中,并從SingletonFactories中remove掉這個ObjectFactory。而對于后續的所有操作都只是為了循環依賴檢測時候使用,也就是allowEarlyReference為true的情況下才使用。
為了解決循環依賴的問題,Spring中創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提前曝光加入到緩存中, 一旦下一個Bean創建時需要依賴上一個bean則直接使用ObjectFactory。
1. 從緩存中獲取單例bean
beans.factory.support.DefaultSingletonBeanRegistry
@Override
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
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 != NULL_OBJECT ? singletonObject : null);
}
簡單解釋一下用于存儲bean的不同的map
- singletonObjects
用于保存BeanName和創建bean實例之間的關系,bean name --> bean instance
- singletonFactories
用于保存BeanName和創建bean的工廠之間的關系,bean name --> ObjectFactory
- earlySingletonObjects
保運BeanName和創建bean實例之間的關系,與singletonObjects的不同在于,當一個單例bean被放到這里面后,name當bean還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用。
- registeredSingletons
用來保存當前所有已注冊的單例bean