在 Spring 中存在着不同的 scope,默認是 singleton,還有prototype等。下面便分析各個scope。
1.singleton。
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);
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
//獲取singletonObjects全局鎖
synchronized (this.singletonObjects) {
//獲取singletonObjects對應的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 + "'");
}
//創建bean之前的處理,添加singletonsCurrentlyInCreation緩存
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//初始化bean 其實就是調用createBean()
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
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;
}
//後置處理,singletonsCurrentlyInCreation除去緩存
afterSingletonCreation(beanName);
}
//添加進入對應的緩存中,刷新對應緩存
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
在isSingleton爲true情況下,getSingleton()和createBean()方法。
分析getSingleton,這個方法並不是核心區創建bean的函數,而是對創建前後進行邏輯操作和校驗。
- 獲取singletonObjects全局鎖,並獲取對應的bean實例,如果bean存在直接返回。這樣可以確保單例模式只存在唯一的 bean實例
- 如果不存在,進行beforeSingletonCreation(beanName),singletonsCurrentlyInCreation加入緩存
-
singletonFactory.getObject()調用createBean()創建bean
- afterSingletonCreation去除singletonsCurrentlyInCreation緩存
- addSingleton()添加刷新對應的緩存。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
一個 put、一個 add、兩個 remove。singletonObjects 單例 bean 的緩存,singletonFactories 單例 beanFactory 的緩存,earlySingletonObjects “早期”創建的單例 bean 的緩存,registeredSingletons 已經註冊的單例緩存。
原型模式:
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
原型模式的創建也是一樣的:
- 調用
beforeSingletonCreation()
記錄加載原型模式 bean 之前的加載狀態,即前置處理。 - 調用
createBean()
創建一個 bean 實例對象。 - 調用
afterSingletonCreation()
進行加載原型模式 bean 後的後置處理。 - 調用
getObjectForBeanInstance()
從 bean 實例中獲取對象。
其他:
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + 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; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
三個模塊最主要的兩個方法createBean()和getObjectForBeanInstance()。createBean()下篇會講解。getObjectForBeanInstance()是這樣解釋的(《Spring 源碼深度解析》):
這個方法主要是驗證以下我們得到的 bean 的正確性,其實就是檢測當前 bean 是否是 FactoryBean 類型的 bean,如果是,那麼需要調用該 bean 對應的 FactoryBean 實例的 getObject()
作爲返回值。無論是從緩存中獲得到的 bean 還是通過不同的 scope 策略加載的 bean 都只是最原始的 bean 狀態,並不一定就是我們最終想要的 bean。舉個例子,加入我們需要對工廠 bean 進行處理,那麼這裏得到的其實是工廠 bean 的初始狀態,但是我們真正需要的是工廠 bean 中定義 factory-method 方法中返回的 bean,而 getObjectForBeanInstance()
就是完成這個工作的。