在Spring源碼系列:BeanDefinition載入(上)中已經大概捋了一下解析過程,本篇將記錄一下bean的註冊過程。java
bean的註冊就是DefaultListableBeanFactory中registerBeanDefinition方法來完成的。那我就來看registerBeanDefinition這個方法的具體邏輯。緩存
一、beanDefinition類型判斷和驗證app
這裏的驗證主要是驗證不能將靜態工廠方法與方法重寫相結合(靜態工廠方法必須建立實例);框架
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(),
beanName,"Validation of bean definition failed", ex);
}
}
複製代碼
二、嘗試從beanDefinitionMap中獲取老的beanpost
這裏就是先根據beanName從beanDefinitionMap去取BeanDefinition,並將結果給oldBeanDefinition。學習
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
複製代碼
三、beanDefinitionMap中已經存在名爲beanName的Beandefinitionthis
若是當前beanDefinitionMap中已經存在名爲beanName的Beandefinition了(即檢查是否有相同名稱的beanDefinition已經在Ioc容器中註冊過了)。,若是有,則進行如下具體策略:spa
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
//省略異常代碼
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
//省略異常代碼
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
//提示覆蓋log信息
}
else {
//提示覆蓋log信息
}
//覆蓋原有的Beandefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
複製代碼
四、beanDefinitionMap不存在名爲beanName的Beandefinitioncode
//檢查bean的建立階段是否已經開始,也就是說是否已經建立了
if (hasBeanCreationStarted()) {
//Cannot modify startup-time collection elements anymore (for stable iteration)
// 沒法修改啓動時間收集元素(用於穩定迭代)(譯註)
//註冊過程須要保證數據的一致性,全部須要加鎖同步
synchronized (this.beanDefinitionMap) {
//註冊到beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
//下面就是將當前beanName存放到beanDefinitionNames中
List<String> updatedDefinitions = new ArrayList<String>(
this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
//若是單例模式的bean名單中有該bean的name,那麼移除掉它。
//也就是說着,將一個本來是單例模式的bean從新註冊成一個普通的bean
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new
LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
// 仍處於啓動階段,bean尚未開始註冊
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
複製代碼
五、執行緩存清除orm
1:oldBeanDefinition若是存在,且執行到了這裏也沒有拋出異常,說明該BeanDefinition已經被覆蓋,緩存須要更新。
2:若是是單例模式的bean對象則Set中包含該beanName,執行到這裏說明該BeanDefinition已經從一個單例模式的bean變爲了一個普通的bean,因此緩存也須要更新。
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
複製代碼
OK,咱們來看下resetBeanDefinition這個方法:
這個方法的做用就是重置給定bean的全部bean定義緩存,包括從它派生的bean的緩存。
protected void resetBeanDefinition(String beanName) {
// 若是已經建立,則刪除給定bean的合併bean定義。
clearMergedBeanDefinition(beanName);
// 若是有的話,從singleton 高速緩存中刪除相應的bean。
//可是這也不是必須的,而只是爲了覆蓋上下文的默認bean
//(就是從manualSingletonNames中移除)
destroySingleton(beanName);
//遞歸的方式來 重置具備給定bean做爲父項的全部bean定義。
for (String bdName : this.beanDefinitionNames) {
if (!beanName.equals(bdName)) {
BeanDefinition bd = this.beanDefinitionMap.get(bdName);
if (beanName.equals(bd.getParentName())) {
resetBeanDefinition(bdName);
}
}
}
}
複製代碼
Bean的註冊就到這裏了,下一篇學習的是DefaultListableBeanFactory這個集大成者容器。