前言
我們都知道在Spring中配置Bean的時候有一個屬性scope,它默認是singleton,還有prototype、request等其它的scope,之前的文章有了解關于singleton的大致的流程,那么其它的步驟是怎么樣的呢?接下來我們進行一下簡單的梳理:
scope之singleton
Spring的scope屬性默認為singleton,上一篇文章分析了在快取中獲取單例模式的Bean,但是如果快取中不存在的呢?則需要從頭開始加載Bean,這個程序有getSingleton()函式實作:
- 看原始碼(
AbstractBeanFactory.java)
if (mbd.isSingleton()) {
// 實體化依賴的Bean后對Bean本身進行實體化
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
);
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
- 原始碼分析
上一篇文章我們主要講解了如何在快取中獲取,但是如果快取中不存在呢?上述代碼就詮釋了如果快取中沒有,它會如何去做,
我們可以看到上述代碼利用了Java 8的新特性lambda運算式() ->,getSingleton方法的第二個引數為**ObjectFactory singletonFactory**,()->相當于創建了一個ObjectFactory型別的匿名內部類,去實作ObjectFactory介面中的getObject()方法,其中**{}**中的代碼相當于寫在匿名內部類中getObject()的代碼片段,等著getSingleton()方法里面通過ObjectFactory singletonFactory去顯式呼叫,如:singletonFactory.getObject(),上述的代碼可以寫成如下格式:
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
}
);
接下來我們進入getSingleton()的方法體中看一下具體實作:
- 看原始碼(
DefaultSingletonBeanRegistry.java)
,public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 加鎖
synchronized (this.singletonObjects) {
// 從快取中檢查一遍
// 因為singleton模式其實就是復用已經創建的,所以這一步很重要必須要檢查,
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 + "'");
}
// 加載前置處理
beforeSingletonCreation(beanName);
Boolean newSingleton = false;
Boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 初始化bean,
// 這個程序就是 AbstractBeanFactory中 sharedInstance = getSingleton(beanName, () -> {...}) 呼叫匿名內部類的方法
// 其實是呼叫 createBean() 方法
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;
}
// 后置處理
afterSingletonCreation(beanName);
}
// 加入快取中
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
// 直接回傳
return singletonObject;
}
- 原始碼決議
上述代碼中我們其實可以看到它使用了回呼方法,使得程式可以在單例創建的前后做一些準備及處理操作,而真正的獲取單例bean的方法其實并不是在此方法中實作的,其實邏輯是在ObjectFactory型別的實體singletonFactory中實作的(即上面的第一段代碼),主要處理操作及內容如下:
- 檢查快取是否已經加載過,
- 如果沒有加載,則記錄beanName的正在加載狀態
- 加載單例前記錄加載狀態,不要覺得beforeSingletonCreation方法是一個空實作,沒有邏輯;其實這個函式做了很重要的操作記錄加載狀態,也就是通過this.singletonsCurrentlyInCreation.add(beanName)將當前正要創建的bean記錄在快取中,這樣便可對回圈依賴進行檢測,具體可以看一下上一篇文章.
ssss
- 通過呼叫引數傳入的ObjectFactory的個體Object方法實體化Bean
- 加載單例Bean后的處理方法呼叫,同步驟3的記錄加載狀態相似,當bean加載結束后需要移除快取中對該Bean的正在加載狀態的記錄,
- 將結果記錄在快取中并且洗掉加載bean程序中所記錄的各種輔助狀態,
- 回傳處理結果,
接著我們在看一下方法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,一個get,兩個remove,
singletonObjects單例bean的快取;
singletonFactories 單例bean Factory;
earlySingletonObjects '早期'創建的單例bean的快取;
registeredSingletons 已經注冊的單例快取;
加載完了單例bean后,呼叫getObjectsForBeanInstance()從bean實體中獲取物件,方法也可以看一下上一邊文章:
dsdfsd
scope之prototype
- 看原始碼(
AbstractBeanFactory.java)
// 原型模式
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
- 原始碼分析
原型模式的初始化程序相對比較簡單一些:直接創建一個新的實體就可以了,程序如下:
- 呼叫
beforeSingletonCreation()記錄加載原型模式bean之前的加載狀態,即前置處理 - 呼叫
createBean()創建一個bean實體物件 - 呼叫
afterSingletonCreation()進行加載原型模式bean后的后置處理 - 呼叫
getObjectForBeanInstance()從bean實體中獲取物件
其它作用域
// 從指定的 scope 模式下創建 Bean
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ′" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
// 具體實作在 SimpleThreadScope 下的get
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
);
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
具體的流程和原型模式基本一樣的,只不過是bean實體是由scope.get()實作,如下:
- 看原始碼(
SimpleThreadScope.java)
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
// 獲取 scope 快取
Map<String, Object> scope = this.threadScope.get();
// NOTE: Do NOT modify the following to use Map::computeIfAbsent. For details,
// see https://github.com/spring-projects/spring-framework/issues/25801.
Object scopedObject = scope.get(name);
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
// 加入快取
scope.put(name, scopedObject);
}
return scopedObject;
}
整理不易,如果對你有所幫助歡迎點贊關注
微信搜索【碼上遇見你】獲取更多精彩內容
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/440480.html
標籤:Java
下一篇:同步鎖筆記
