Spring原始碼03---parseDefaultElement
首先讓我們回到https://www.cnblogs.com/xiaomaomao/p/14106990.html文末的 parseBeanDefinitions方法,這個方法主要是解析 beans 標籤下面預設的標籤(beans、import、alias、bean)
程式碼塊一、parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
// DefaultBeanDefinitionDocumentReader 類中的方法 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 1、判斷當前是否是預設的名稱空間, Spring 配置檔案預設的名稱空間如下: // xmlns="http://www.springframework.org/schema/beans" ,因為它不包含字首 xnlns:字首 if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { // 1.1、解析預設名稱空間下面的預設元素,包括 import、alias、beans、bean ---- (詳情見程式碼塊二) parseDefaultElement(ele, delegate); } else { // 1.2、解析預設名稱空間下面的自定義元素,包括 context、tx... 等 delegate.parseCustomElement(ele); } } } } else { // 2、解析自定義名稱空間下的元素 delegate.parseCustomElement(root); } }
本文主要是為了弄清楚 Spring 是如何解析這些預設的元素的,對應的程式碼是parseDefaultElement(ele, delegate), 這裡麵包含了 Spring beans 標籤下的所有預設的標籤的解析,包括我們最常用,也最重要的 bean 標籤的解析
程式碼塊二、parseDefaultElement(ele, delegate)
// DefaultBeanDefinitionDocumentReader 類中的方法 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { // 1、解析 import 標籤 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } // 2、解析 alias 標籤 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } // 3、解析 bean 標籤,這個是我們最常用也最核心的,因為我們在 Spring 配置檔案中配置最多的就是 bean 標籤 // 注意:這裡解析的是 beans 標籤中的一個 bean 標籤 // 我們這裡就著重看一下是如何解析 bean 標籤的 ---- (詳細見程式碼塊三) else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } // 4、解析 beans 標籤 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 4.1、遞迴呼叫,因為預設的名稱空間是 beans , beans 標籤中是可以巢狀 beans 標籤的 // 所以需要遞迴呼叫解析 beans 標籤裡面的 beans 標籤裡面的標籤 doRegisterBeanDefinitions(ele); } }
程式碼塊三、processBeanDefinition(ele, delegate)
// DefaultBeanDefinitionDocumentReader 類中的方法 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 1、解析一個 bean 標籤,並且將解析好的資料封裝在 BeanDefinitionHolder 物件中 ---- (詳情見程式碼塊四) BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 2、若存在預設標籤的子節點下再有自定義屬性,需要再次對自定義標籤再進行解析(基本不用,不做深入解析) bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 3、註冊 BeanDefinition ---- (詳情見程式碼塊八) BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // 4、傳送註冊事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
在解析 bean 標籤之前,我們先去看一下我們用的最多的 bean 標籤,它裡面到底可以配置什麼資訊.
bean 標籤中可以配置的屬性如下:
bean 標籤中可以配置的子標籤如下:
在執行 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele) 這句程式碼之前,我們需要去看一下BeanDefinitionHolder 這個類,開啟這個類,可以發現這個類總共就只有三個屬性, beanName、aliases、beanDefinition ,其中最重要的就是 beanDefinition,它封裝的是 bean 定義資訊,也就是它可以封裝 bean 標籤中的除了 id 、name屬性之外的所有屬性,以及封裝 bean 標籤下面的子標籤中的資料資訊
然後我們再去看一下 BeanDefinition 這個類,並且結合上圖中的 bean 標籤裡面可以配置的屬性值一起看,我們會發現, BeanDefiniton 實際上可以看做是對應 bean 標籤的一個例項.
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 1、預設的 scope 只支援 singleton 和 prototype 兩種,
// request, session, globalSession, application, websocket ... 這些屬於 web 的擴充套件
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// 2、應用的角色
int ROLE_APPLICATION = 0;
// 3、支援的角色
int ROLE_SUPPORT = 1;
// 4、基礎架構角色
int ROLE_INFRASTRUCTURE = 2;
// 5、獲取父 bean ,這裡的父 bean ,不是 java 中繼承關係的父類,它代表的是繼承父 bean 中的屬性
// 對應的是 bean 標籤中的 parent 屬性,定義父 bean 僅僅是為了繼承父 bean 的屬性而已,子 bean 和
// 父 bean 不需要存在繼承關係
String getParentName();
// 6、設定 Bean 的類名稱,將來是要通過反射來生成例項的
void setBeanClassName(String beanClassName);
String getBeanClassName();
// 7、設定 bean 的 scope 屬性
void setScope(String scope);
String getScope();
void setLazyInit(boolean lazyInit);
// 8、設定是否懶載入初始化
boolean isLazyInit();
// 9、設定該 Bean 依賴的所有的 Bean ,注意:這裡的依賴不是指屬性依賴(如 @Autowire 標記的)
// 而是 bean 標籤裡面的 depends-on="" 屬性設定的值.
void setDependsOn(String... dependsOn);
String[] getDependsOn();
void setAutowireCandidate(boolean autowireCandidate);
// 10、是否可以通過 @Atuowired 自動裝配
boolean isAutowireCandidate();
void setPrimary(boolean primary);
// 11、是否是主要的,同一介面的多個實現,如果不指定名字的話, Spring 會優先選擇設定 primary 為 true 的 bean
boolean isPrimary();
// 12、設定工廠 bean 的名稱,在 Spring 中,不是所有的 bean 都是通過反射生成的,也可以通過工廠 bean 來生成
void setFactoryBeanName(String factoryBeanName);
String getFactoryBeanName();
// 13、設定工廠 bean 的方法名
void setFactoryMethodName(String factoryMethodName);
String getFactoryMethodName();
// 14、構造引數注入值
ConstructorArgumentValues getConstructorArgumentValues();
// 15、Property 屬性注入值
MutablePropertyValues getPropertyValues();
boolean isSingleton();
boolean isPrototype();
// 16、如果這個 Bean 是被設定為 abstract ,那麼不能例項化,常用於作為父 bean 用於繼承,其實也很少用......
boolean isAbstract();
int getRole();
String getDescription();
String getResourceDescription();
BeanDefinition getOriginatingBeanDefinition();
}
看完了BeanDefinitionHolder 和 BeanDefinition,我們接著回到程式碼吧
程式碼塊四、parseBeanDefinitionElement(ele)
// BeanDefinitionParserDelegate 類中的方法
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
// 1、獲取該 bean 標籤中的 id 屬性值
String id = ele.getAttribute(ID_ATTRIBUTE);
// 2、獲取 bean 標籤的 name 屬性值
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 3、如果 bean 標籤中配置了<bean name="m1,m2;m3;m4" class="com.xiaomaomao.entity.Mango" >
// 它會使用 , ; 進行分割,並且將分割後的 m1 m2 m3 m4 存入 List 集合 aliases 中
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 4、將 id 值賦值給 beanName 屬性
String beanName = id;
// 5、如果 bean 標籤中沒有配置 id 屬性,只配置了 name 屬性
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
// 5.1、那麼就將 name 屬性的第一個值作為 beanName , 剩下的作為 別名
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
// 6、校驗 beanName 和 aliases 的唯一性
checkNameUniqueness(beanName, aliases, ele);
}
// 7、解析 bean 定義元素 ---- (詳情見程式碼塊五)
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 8、如果 bean 標籤中既沒有配置 id 也沒有配置 name 屬性
// <bean class="com.xiaomaomao.entity.Mango">
if (!StringUtils.hasText(beanName)) {
try {
// 8.1、如果包含內部 bean 的情況下
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
// 8.2 、不包含內部 bean 的情況下, Spring 會根據自己的規則生成 beanName
// beanName : com.xiaomaomao.entity.Mango#0
beanName = this.readerContext.generateBeanName(beanDefinition);
// 8.3、使用 beanClassName 作為別名
// beanClassName : com.xiaomaomao.entity.Mango
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
// 9、將存放所有別名的 List 集合轉化為 String 型別的陣列
String[] aliasesArray = StringUtils.toStringArray(aliases);
// 10、返回 BeanDefinitionHolder 物件
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
程式碼塊五、parseBeanDefinitionElement(ele, beanName, containingBean)
// BeanDefinitionParserDelegate 類中的方法
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
// 1、將 beanName 封裝進 BeanEntry 的 beanDefinitionName 屬性中,然後再存入本類的 ParseState 中
this.parseState.push(new BeanEntry(beanName));
String className = null;
// 2、如果 bean 標籤中配置了 class 屬性,獲取到 class 屬性配置的值
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
// 3、判斷 bean 標籤中是否配置了 parent 屬性
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
// 4、建立一個可以承載 bean 標籤資料的 AbstractBeanDefinition 物件,並設定 beanClass 屬性 ---- (詳情見程式碼塊六)
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 5、解析 bean 標籤的剩餘屬性 ---- (詳情見程式碼塊七)
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 6、封裝 description 屬性
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 7、解析 bean 標籤裡面的 meta 標籤
parseMetaElements(ele, bd);
// 8、解析 bean 標籤裡面的 lookup - method 標籤
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 9、解析 bean 標籤裡面的 replace - method 標籤
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 10、解析 bean 標籤裡面的 constructor-arg 標籤,這個標籤很重要,當我們使用有引數構造方法注入值的時候使用該標籤
// 對 bean 物件裡面的屬性賦值,如果沒有有引數構造方法,那麼會報錯
parseConstructorArgElements(ele, bd);
// 11、解析 bean 標籤裡面的 property 標籤,這個標籤也很重要,使用 無引數構造方法 和 setxxx 方法對 bean 物件進行賦值
parsePropertyElements(ele, bd);
// 12、解析 bean 標籤裡面的 qualifier 標籤
parseQualifierElements(ele, bd);
// 13、設定當前 Spring 配置檔案的資源路徑
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
// 14、移除 ParseState 中之前存入的 BeanDefinitionName
this.parseState.pop();
}
return null;
}
程式碼塊六、createBeanDefinition(className, parent)
// BeanDefinitionParserDelegate 類中的方法
protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
// BeanDefinitionReaderUtils 類中的方法
public static AbstractBeanDefinition createBeanDefinition(
String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
// 1、新建一個 GenericBeanDefinition 物件用於承載資料,它是 AbstractBeanDefinition 的子類
GenericBeanDefinition bd = new GenericBeanDefinition();
// 2、設定 parentName
bd.setParentName(parentName);
// 3、如果 bean 標籤中配置了 class 屬性
if (className != null) {
if (classLoader != null) {
// 3.1、如果 classLoader 不為空,使用反射構建出 BeanClass ,並設定為 GenericBeanDefinition 的屬性.
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
// 3.2、如果 classLoader 為空,將 className 設定為 GenericBeanDefinition 的屬性.
bd.setBeanClassName(className);
}
}
// 4、返回 GenericBeanDefinition 物件
return bd;
}
程式碼塊七、parseBeanDefinitionAttributes(ele, beanName, containingBean, bd)
// BeanDefinitionParserDelegate 類中的方法
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 1、對於 1.0 版本的 singleton 屬性 bean 標籤已經不支援了,如果你想使用,必須要用 scope="singleton" 去宣告
// 否則會報錯,當然 Spring 預設 bean 的 scope 就是 singleton
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
}
// 2、將 bean 標籤中的 scope 屬性對應的值使用 GenericBeanDefinition 物件進行封裝
else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
}
// 3、在內部bean定義的情況下,從包含bean接受預設值.
else if (containingBean != null) {
bd.setScope(containingBean.getScope());
}
// 4、GenericBeanDefinition 物件封裝 bean 的 abstract 屬性
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
// 5、Spring 預設不使用懶載入,如果你想使用懶載入初始化,它的值為 false ,如果需要在 bean 標籤上明確規定為 true
// <bean id="mango" name="m1,m2;m3;m4" class="com.xiaomaomao.entity.Mango" lazy-init="true">
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (DEFAULT_VALUE.equals(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
// 6、封裝 autowire 屬性
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
// 7、封裝 dependency-check 屬性
String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
// 8、封裝 depends-on 屬性
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
// 9、封裝 autowire-candidate 屬性
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
// 10、封裝 primary 屬性
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
// 11、封裝 init-method 屬性
if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
if (!"".equals(initMethodName)) {
bd.setInitMethodName(initMethodName);
}
}
else {
if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
}
// 12 、封裝 destroy-method 屬性
if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
bd.setDestroyMethodName(destroyMethodName);
}
else {
if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
}
// 13、封裝 factory-method 屬性
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
// 14、封裝 factory-bean 屬性
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
// 15、返回封裝了 bean 標籤中所有屬性的 GenericBeanDefinition 物件
return bd;
}
讓我們回到 解析一個 bean 標籤開始的位置BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
// DefaultBeanDefinitionDocumentReader 類中的方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 1、解析一個 bean 標籤,並且將解析好的資料封裝在 BeanDefinitionHolder 物件中 ---- (詳情見程式碼塊四)
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 2、若存在預設標籤的子節點下再有自定義屬性,需要再次對自定義標籤再進行解析(基本不用,不做深入解析)
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 3、註冊 BeanDefinition ---- (詳情見程式碼塊八)
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 4、傳送註冊事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
到這裡為止整個BeanDefinitionHolder 物件就全部解析出來了,裡面封裝了 beanName、aliases、以及 BeanDefinition 物件.
程式碼塊八、registerBeanDefinition(bdHolder, getReaderContext().getRegistry())
// BeanDefinitionReaderUtils 類中的方法
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 1、獲取 beanName
String beanName = definitionHolder.getBeanName();
// 2、註冊 bean 定義 ---- (詳情見程式碼塊九)
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 3、獲取所有的別名 ---- (詳情見程式碼塊十一)
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
// 4、依次獲取每一個別名,然後註冊別名
registry.registerAlias(beanName, alias);
}
}
}
程式碼塊九、registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())
// DefaultListableBeanFactory 類中的方法 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); // 1、我們前面建立的是一個 GenericBeanDefinition 的物件用來承載資料 if (beanDefinition instanceof AbstractBeanDefinition) { try { // 2、校驗 beanDefinition ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } // 3、這裡定義一個 oldBeanDefinition 主要是 bean 是否可以覆蓋,我們在同一個 Spring 配置檔案中是不能定義 // 兩個相同 bean 的,但是可以在不同的配置檔案中定義相同的 bean , // Spring 預設 bean 可以覆蓋,即如果存在兩個相同名稱的 bean ,後加載的那個 bean 覆蓋先載入的 bean BeanDefinition oldBeanDefinition; // 4、通過 beanName 從 beanDefinitionMap 快取中獲取 beanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName); // 5、如果已經存在了 beanDefinition if (oldBeanDefinition != null) { // 5.1、Spring 預設是可以 bean 覆蓋的,但是如果設定了不可以進行 bean 覆蓋,那麼就丟擲異常 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } // 5.2、根據 Role 值進行判斷,ROLE_APPLICATION=0 ROLE_SUPPORT=1 ROLE_INFRASTRUCTURE=2 else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } // 5.3、如果前後載入的兩個 beanDefinition 內容不同 (這裡的新、舊 beanDefinition 只是 beanName 相同) else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } // 5.4、使用新載入的 beanDefinition 覆蓋原先 beanDefinitionMap 快取中的 oldBeanDefinition // {beanName:oldBeanDefinition} ----> {beanName:beanDefinition} this.beanDefinitionMap.put(beanName, beanDefinition); } // 6、如果 beanDefinitionMap 快取中不存在 beanName else { // 7、如果建立 Bean 已經開始了 if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) // 7.1、加鎖 synchronized (this.beanDefinitionMap) { // 7.2、將本次傳進來的 beanName 和 BeanDefinition 對映放入 beanDefinitionMap 快取 this.beanDefinitionMap.put(beanName, beanDefinition); // 7.3、將本次傳進來的 beanName 加入beanDefinitionNames 快取 List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 7.4、如果 manualSingletonNames 包含 beanName ,將 beanName 從 manualSingletonNames 移除 if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } // 8、目前在註冊階段,還沒有到建立 bean 階段,我們這裡是初次啟動專案,肯定沒有建立 bean else { // Still in startup registration phase // 8.1、將 beanName beanDefinition 以鍵值對的形式存入 beanDefinitionMap 快取中 this.beanDefinitionMap.put(beanName, beanDefinition); // 8.2、將 beanName 存入 beanDefinitionNames 快取中 this.beanDefinitionNames.add(beanName); // 8.3、移除 manualSingletonNames 快取中的 beanName this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } // 9、如果存在相同 beanName 的 BeanDefinition,並且 beanName 已經存在單例物件,則將該 beanName 對應的快取資訊、單例物件清除, // 因為這些物件都是通過 oldBeanDefinition 創建出來的,需要使用新的 BeanDefinition 覆蓋掉 // 我們需要用新的 BeanDefinition(也就是本次傳進來的 beanDefinition)來建立這些快取和單例物件 // (詳情見程式碼塊十) if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
程式碼塊十、resetBeanDefinition(beanName)
// DefaultListableBeanFactory 類中的方法
protected void resetBeanDefinition(String beanName) {
// Remove the merged bean definition for the given bean, if already created.
// 1、刪除 beanName 的 mergedBeanDefinitions 快取(如果有的話)
clearMergedBeanDefinition(beanName);
// Remove corresponding bean from singleton cache, if any. Shouldn't usually
// be necessary, rather just meant for overriding a context's default beans
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
// 2、從單例快取中刪除該 beanName 對應的 bean(如果有的話)
destroySingleton(beanName);
// Reset all bean definitions that have the given bean as parent (recursively).
// 3.重置 beanName 的所有子 Bean 定義(遞迴)
for (String bdName : this.beanDefinitionNames) {
if (!beanName.equals(bdName)) {
BeanDefinition bd = this.beanDefinitionMap.get(bdName);
// 當前遍歷的 BeanDefinition 的 parentName 為 beanName,則遞迴呼叫 resetBeanDefinition 進行重置
if (beanName.equals(bd.getParentName())) {
resetBeanDefinition(bdName);
}
}
}
}
程式碼塊十一、resetBeanDefinition(bdName)
// SimpleAliasRegistry 類中的方法
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
// 1、如果 beanName 和別名相同,則 alias 無效,從 aliasMap 快取中移除
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}
else {
// 2、通過 alias 從 aliasMap 快取中獲取 beanName
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
// 3、校驗通過 alias 獲取到的 beanName 和傳進來的 beanName 是否相等,如果相等,代表已經別名已經註冊了,無需再註冊
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
// 4、如果不允許別名覆蓋,則丟擲異常
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
}
// 5、校驗 name 和 alias 是否迴圈引用
checkForAliasCircle(name, alias);
// 6、將 alias beanName 的鍵值對存入 aliasMap 快取中
this.aliasMap.put(alias, name);
}
}
到這裡,一個 bean 標籤的解析已經完成了,程式碼回到了這裡
總結:
1、我們可以重新梳理一下思路,我們首先將 Spring 配置檔案 xml中的 bean 配置資訊進行了解析,並構建了 AbstractBeanDefinition (GenericBeanDefinition ) 物件來存放所有解析出來的 bean 標籤的所有屬性和 bean 標籤下面的子標籤中的資訊.
2、然後,我們將 AbstractBeanDefinition、beanName、aliasesArray構建成 BeanDefinitionHolder物件並返回.
3、最後,我們通過BeanDefinitionHolder將BeanDefinition和beanName 註冊到BeanFactory中,也就是存放到快取中。
執行完 parseDefaultElement 方法,我們得到了兩個重要的快取:
beanDefinitionNames [beanName] 快取
beanDefinitionMap{beanName:beanDefinition}快取
參考:https://blog.csdn.net/v123411739/article/details/86669952