在上一篇文章图甜,我們講了 IoC 容器初始化的準(zhǔn)備階段蜕衡,即找到 BeanDefinition 的 Resource 定位突硝,就好比我們用水桶打水,首先要找到水源所在蛮瞄。找到水源之后所坯,我們關(guān)注的就是打水的過程了,相比于之前挂捅,這個(gè)過程更加的精妙芹助,下面我們一起來了解一下 IoC 容器初始化的第二個(gè)過程: BeanDefinition 的載入和解析
-
BeanDefinition 的載入和解析
在完成對(duì) BeanDefinition 的 Resource 定位的分析之后,接下來我們來了解整個(gè) BeanDefinition 信息的載入過程。對(duì)于 IoC 容器而言状土,這個(gè)載入相當(dāng)于把定義的 BeanDefinition 在 IoC 容器中轉(zhuǎn)化成 Spring 內(nèi)部表示的數(shù)據(jù)結(jié)構(gòu)的過程无蜂。 IoC 容器對(duì) Bean 的管理和依賴注入功能的實(shí)現(xiàn),是通過其持有的 BeanDefinition 進(jìn)行各種相關(guān)操作來完成的蒙谓。這些 BeanDefinition 數(shù)據(jù)在 IoC 容器中通過一個(gè) HashMap 來保持和維護(hù)斥季。下面,我們從源碼出發(fā)來看一下 IoC 容器是如何對(duì) BeanDefinition 載入的累驮。
BeanDefinition 載入的具體交互過程如下:
BeanDefinition 載入交互過程- 在上一篇文章中我們說過酣倾,refresh() 是一個(gè)非常重要的方法,是 IoC 容器初始化的入口谤专,那么我們找到其實(shí)現(xiàn)的源碼躁锡。它首先是在 FileSystemXmlApplicationContext 中調(diào)用,并在 AbstractApplicationContext 中被實(shí)現(xiàn)置侍。
該方法詳細(xì)地描述了整個(gè) ApplicationContext 的初始化過程蜡坊,比如 BeanFactory 的更新等杠输,可以看成是對(duì) ApplicationContext 初始化的模板或執(zhí)行提綱,這個(gè)執(zhí)行為 Bean 的生命周期管理提供了條件算色。熟悉 IoC 容器使用的讀者抬伺,從這一系列調(diào)用的名字大概就能了解整個(gè) ApplicationContext 初始化的主要內(nèi)容。同時(shí)在 try-catch 之前灾梦,我們可以看到首先調(diào)用了 obtainBeanFactory 方法來獲取一個(gè) BeanFactory峡钓,我們進(jìn)去看一下發(fā)生了什么。public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // 為防止資源占用映之,在異常處理中,銷毀掉前面已經(jīng)生成的單例 Bean destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
- 最終到 AbstractRefreshableApplicationContext 類的 refreshBeanFactory() 方法:
在該方法中若河,首先判斷是否已經(jīng)存在了基礎(chǔ)的 BeanFactory 容器能岩,有的話就銷毀。接著調(diào)用 createBeanFactory() 方法創(chuàng)建了一個(gè) DefaultListableBeanFactory萧福。這也驗(yàn)證了我們?cè)谏弦晃恼f到的拉鹃,ApplicationContext 是在基礎(chǔ) BeanFactory 上添加了高級(jí)容器特征的 IoC 容器,而且大多數(shù)情況下是使用 DefaultListableBeanFactory 這個(gè)具有基礎(chǔ)容器功能的 BeanFactory鲫忍。protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
- 接著最主要的就是 loadBeanDefinitions() 方法膏燕,但是在這里這只是一個(gè)抽象方法,在上面的交互圖我們可以看到悟民,其具體實(shí)現(xiàn)是在 AbstractXmlApplicationContext 中實(shí)現(xiàn)的坝辫。
其實(shí)到了這里近忙,如果在上面有親自動(dòng)手追蹤 BeanDefinition 的 Resource 定位的讀者竭业,應(yīng)該會(huì)對(duì)當(dāng)前 AbstractXmlApplicationContext 這個(gè)類比較熟悉,因?yàn)槲覀兩厦嫣岬降墨@取 configuration 也是 在這個(gè)類中調(diào)用的及舍。這更加可以說明 refresh() 是 IoC 容器初始化的如果未辆,畢竟在上一個(gè)步驟中我們并沒有進(jìn)入到 refresh() 這個(gè)方法里面去查看。protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 創(chuàng)建一個(gè) XmlBeanDefinitionReader,并通過回調(diào)設(shè)置到 BeanFactory 中去射亏。 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
- 接著就是 loadBeanDefinitions 調(diào)用的地方锯玛,首先得到 BeanDefinition 的 Resource 定位咐柜,其具體過程已經(jīng)在上文講過,我們就不再介紹了更振,代碼清單如下:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
- 通過對(duì)以上實(shí)現(xiàn)原理的分析炕桨,我們可以看到,refresh() 方法啟動(dòng)對(duì) IoC 容器的初始化肯腕,具體的過程是在 XmlBeanDefinitionReader 中完成的献宫。因?yàn)?Spring 對(duì)應(yīng)不用形式的 BeanDefinition,這里使用的是 XML 方式定義实撒,所以需要使用 XmlBeanDefinitionReader姊途,如果使用了其他 BeanDefinition 方式,就需要使用其他中來的 BeanDefinitionReader 來完成載入工作知态。這里 XmlBeanDefinitionReader 的父類 AbstractBeanDefinitionReader 已經(jīng)為這個(gè)載入工作做好了準(zhǔn)備捷兰。代碼如下:
但是這里 loadBeanDefinitions 僅僅是一個(gè)接口方法,具體的實(shí)現(xiàn)交由各個(gè)子類去完成负敏。下面我們進(jìn)去到 XmlBeanDefinitionReader 去查看實(shí)現(xiàn)過程贡茅。public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; }
- 我們看一下源碼:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } // 這里得到XML 文件,并得到 IO 的 InputStream 準(zhǔn)備進(jìn)行讀取其做。 try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
- 具體的讀取過程可以在 doLoadBeanDefinitions() 方法中找到顶考。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } }
- 感興趣的讀者可以到 DefaultDocumentLoader 里面看看如何得到 Document 對(duì)象,這里就不詳細(xì)分析的妖泄。我們關(guān)系的是 Spring 的 BeanDefinition 是如何按照 Spring 的 Bean 語義要求進(jìn)行解析并轉(zhuǎn)化成容器內(nèi)部數(shù)據(jù)結(jié)構(gòu)的驹沿。這個(gè)過程是在 registerBeanDefinitions() 方法實(shí)現(xiàn)的,還對(duì)載入的 Bean 數(shù)量進(jìn)行了統(tǒng)計(jì)蹈胡。
可以看到渊季,這個(gè)解析過程是在 documentReader 里面進(jìn)行的,這里使用的是 DefaultBeanDefinitionDocumentReader罚渐。public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(this.getEnvironment()); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
- 我們繼續(xù)追蹤 registerBeanDefinitions() 方法却汉,并結(jié)合最上面的交互過程,得到方法調(diào)用棧圖下圖所示:
image
我們首先進(jìn)入到 DefaultBeanDefinitionDocumentReader 里面荷并,可以看到 processBeanDefinition 方法中病涨,調(diào)用了 BeanDefinitionParserDelegate 來最終完成這個(gè)整個(gè)解析過程,得到的結(jié)果由 BeanDefinitionHolder 來持有璧坟,源碼清單如下:
BeanDefinitionHolder 是 BeanDefinition 對(duì)象類的封裝類既穆,封裝了 BeanDefinition、Bean 的名字和別名雀鹃,用它來向 IoC 容器注冊(cè)幻工。而具體的解析過程交由 BeanDefinitionParserDelegate 完成,感興趣的讀者可以繼續(xù)仔細(xì)最終研究黎茎。下面我們舉個(gè)例子來分析一下囊颅。protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
- 我們看一下源碼:
- 我們先來看一下最常見的 Bean 元素解析:
在這里我們會(huì)看到 XML 定義文件常見到的屬性元素,如 id嗅骄、name胳挎、aliase 等,把這些元素從 XML 文件轉(zhuǎn)化而來的 element 中取出來溺森,并設(shè)置到 BeanDefinitionHolder 中去慕爬,這些屬性的解析還是比較簡(jiǎn)單的。對(duì)于其他元素配置的解析屏积,如各種 Bean 的屬性配置医窿,則為一個(gè)較為復(fù)雜的過程,由 parseBeanDefinitionElement 方法完成炊林。public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // 這里取得 bean 元素定義里面 id、name傅瞻、aliase 屬性的值踢代。 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { 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) { checkNameUniqueness(beanName, aliases, ele); } // 這個(gè)方法引發(fā)對(duì) bean 元素的詳細(xì)解析 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); 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; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
- 以上介紹了對(duì) Bean 元素進(jìn)行解析的過程姥卢。也就是 BeanDefinition 根據(jù) XML 的 <bean> 定義被創(chuàng)建的過程。這個(gè) BeanDefinition 可以看成 <bean> 定義的抽象渣聚。這個(gè)數(shù)據(jù)對(duì)象中封裝的數(shù)據(jù)大都是與 <bean> 定義相關(guān)的独榴,也就是我們?cè)诙x Bean 時(shí)看到的那些 Spring 標(biāo)記,如 init-method饵逐、destroy-method 等括眠。這個(gè) BeanDefinition 數(shù)據(jù)類型是非常重要的,它封裝了很多基本數(shù)據(jù)倍权,這些基本數(shù)據(jù)都是 IoC 容器需要的掷豺。 BeanDefinition 是 IoC 容器中非常核心的數(shù)據(jù)結(jié)構(gòu),而通過上述的解析薄声,這些數(shù)據(jù)已經(jīng)準(zhǔn)備好在 IoC 容器中大顯身手了当船。
- 下面我們?cè)俳又櫍M(jìn)入 parseBeanDefinitionElement 源碼之中:
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 這里對(duì)當(dāng)前的 Bean 元素進(jìn)行屬性分析默辨,并設(shè)置描述信息德频。 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // 從名字可以看出,這里是對(duì)各種 <bean> 元素的信息進(jìn)行解析的地方缩幸。 parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); 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 { this.parseState.pop(); } return null; }
- 上面是具體生成 BeanDefinition 的地方壹置。在這里竞思,我們舉一個(gè)對(duì) property 進(jìn)行解析的例子,最終完成對(duì)整個(gè) BeanDefinition 載入和解析的過程钞护。這里是指對(duì) Bean 元素下的 property 子元素進(jìn)行解析盖喷。
public void parsePropertyElements(Element beanEle, BeanDefinition bd) { // 遍歷 Bean 元素下的定義的 property NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { // 進(jìn)行詳細(xì)的解析 parsePropertyElement((Element) node, bd); } } }
public void parsePropertyElement(Element ele, BeanDefinition bd) { / 這里取得 property 的名字。 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); // 這里是解析 property 的過程难咕。返回的對(duì)象對(duì)應(yīng)在 Bean 中定義的 property 屬性的解析結(jié)果课梳,這個(gè)結(jié)果會(huì)封裝到 PropertyValue 中。 try { if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } }
// 這里取得 peoperty 元素的值 public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; } }
property 子元素的解析椭懊,最終會(huì)生成對(duì)應(yīng)的數(shù)據(jù)對(duì)象,比如 ManagedList雾消、ManagedArray灾搏、ManagedSet等,這些 Managed 類是 Spring 的具體的 BeanDefinition 的數(shù)據(jù)封裝立润。具體的過程讀者可以去查看具體的解析過程狂窑。從一系列 parse 方法名字可以很清楚的看出是對(duì)哪種類型的解析,具體的過程我們就不再查看了桑腮。// 這里是對(duì) property 子元素的解析過程余佃,Array暮刃、List、Set爆土、Map 等元素都會(huì)在這里解析 public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in a parent context. refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) { // It's a distinguished null value. Let's wrap it in a TypedStringValue // object in order to preserve the source location. TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }
- 在上一篇文章中我們說過酣倾,refresh() 是一個(gè)非常重要的方法,是 IoC 容器初始化的入口谤专,那么我們找到其實(shí)現(xiàn)的源碼躁锡。它首先是在 FileSystemXmlApplicationContext 中調(diào)用,并在 AbstractApplicationContext 中被實(shí)現(xiàn)置侍。
這樣逐層的解析泉哈,我們?cè)?XML 定義的 BeanDefinition 就被整個(gè)載入到 IoC 容器中,并在容器中建立了數(shù)據(jù)映射破讨,即在 IoC 容器創(chuàng)建了對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)丛晦,這些數(shù)據(jù)結(jié)構(gòu)以 AbstractBeanDefinition 為入口,讓 IoC 容器進(jìn)行索引提陶、查詢和操作烫沙。但是,重要的依賴注入實(shí)際上還沒有發(fā)生隙笆,現(xiàn)在 IoC 容器 BeanDefinition 中存在的還只是一些靜態(tài)的配置锌蓄。嚴(yán)格來說,這時(shí)候的容器還沒有完全起作用撑柔,要完全發(fā)揮容器的作用瘸爽,還需要完成數(shù)據(jù)向容器的注冊(cè)。