美文网首页程序员首页投稿
IoC 容器的初始化之 BeanDefinition 的载入和

IoC 容器的初始化之 BeanDefinition 的载入和

作者: 偷星辰夜 | 来源:发表于2017-11-27 12:59 被阅读0次

    在上一篇文章,我们讲了 IoC 容器初始化的准备阶段,即找到 BeanDefinition 的 Resource 定位,就好比我们用水桶打水,首先要找到水源所在。找到水源之后,我们关注的就是打水的过程了,相比于之前,这个过程更加的精妙,下面我们一起来了解一下 IoC 容器初始化的第二个过程: BeanDefinition 的载入和解析

    • BeanDefinition 的载入和解析

      在完成对 BeanDefinition 的 Resource 定位的分析之后,接下来我们来了解整个 BeanDefinition 信息的载入过程。对于 IoC 容器而言,这个载入相当于把定义的 BeanDefinition 在 IoC 容器中转化成 Spring 内部表示的数据结构的过程。 IoC 容器对 Bean 的管理和依赖注入功能的实现,是通过其持有的 BeanDefinition 进行各种相关操作来完成的。这些 BeanDefinition 数据在 IoC 容器中通过一个 HashMap 来保持和维护。下面,我们从源码出发来看一下 IoC 容器是如何对 BeanDefinition 载入的。

      BeanDefinition 载入的具体交互过程如下

      BeanDefinition 载入交互过程
      • 在上一篇文章中我们说过,refresh() 是一个非常重要的方法,是 IoC 容器初始化的入口,那么我们找到其实现的源码。它首先是在 FileSystemXmlApplicationContext 中调用,并在 AbstractApplicationContext 中被实现。
        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) {
                    // 为防止资源占用,在异常处理中,销毁掉前面已经生成的单例 Bean 
                    destroyBeans();
        
                    // Reset 'active' flag.
                    cancelRefresh(ex);
        
                    // Propagate exception to caller.
                    throw ex;
                }
            }
        }
        
        该方法详细地描述了整个 ApplicationContext 的初始化过程,比如 BeanFactory 的更新等,可以看成是对 ApplicationContext 初始化的模板或执行提纲,这个执行为 Bean 的生命周期管理提供了条件。熟悉 IoC 容器使用的读者,从这一系列调用的名字大概就能了解整个 ApplicationContext 初始化的主要内容。同时在 try-catch 之前,我们可以看到首先调用了 obtainBeanFactory 方法来获取一个 BeanFactory,我们进去看一下发生了什么。
      • 最终到 AbstractRefreshableApplicationContext 类的 refreshBeanFactory() 方法:
        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);
            }
        }
        
        在该方法中,首先判断是否已经存在了基础的 BeanFactory 容器,有的话就销毁。接着调用 createBeanFactory() 方法创建了一个 DefaultListableBeanFactory。这也验证了我们在上一文说到的,ApplicationContext 是在基础 BeanFactory 上添加了高级容器特征的 IoC 容器,而且大多数情况下是使用 DefaultListableBeanFactory 这个具有基础容器功能的 BeanFactory。
      • 接着最主要的就是 loadBeanDefinitions() 方法,但是在这里这只是一个抽象方法,在上面的交互图我们可以看到,其具体实现是在 AbstractXmlApplicationContext 中实现的。
        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // 创建一个 XmlBeanDefinitionReader,并通过回调设置到 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);
        }
        
        其实到了这里,如果在上面有亲自动手追踪 BeanDefinition 的 Resource 定位的读者,应该会对当前 AbstractXmlApplicationContext 这个类比较熟悉,因为我们上面提到的获取 configuration 也是 在这个类中调用的。这更加可以说明 refresh() 是 IoC 容器初始化的如果,毕竟在上一个步骤中我们并没有进入到 refresh() 这个方法里面去查看。
      • 接着就是 loadBeanDefinitions 调用的地方,首先得到 BeanDefinition 的 Resource 定位,其具体过程已经在上文讲过,我们就不再介绍了,代码清单如下:
        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);
            }
        }
        
      • 通过对以上实现原理的分析,我们可以看到,refresh() 方法启动对 IoC 容器的初始化,具体的过程是在 XmlBeanDefinitionReader 中完成的。因为 Spring 对应不用形式的 BeanDefinition,这里使用的是 XML 方式定义,所以需要使用 XmlBeanDefinitionReader,如果使用了其他 BeanDefinition 方式,就需要使用其他中来的 BeanDefinitionReader 来完成载入工作。这里 XmlBeanDefinitionReader 的父类 AbstractBeanDefinitionReader 已经为这个载入工作做好了准备。代码如下:
        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;
        }
        
        但是这里 loadBeanDefinitions 仅仅是一个接口方法,具体的实现交由各个子类去完成。下面我们进去到 XmlBeanDefinitionReader 去查看实现过程。
        • 我们看一下源码:
          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 准备进行读取。
              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 对象,这里就不详细分析的。我们关系的是 Spring 的 BeanDefinition 是如何按照 Spring 的 Bean 语义要求进行解析并转化成容器内部数据结构的。这个过程是在 registerBeanDefinitions() 方法实现的,还对载入的 Bean 数量进行了统计。
          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;
          }
          
          可以看到,这个解析过程是在 documentReader 里面进行的,这里使用的是 DefaultBeanDefinitionDocumentReader。
        • 我们继续追踪 registerBeanDefinitions() 方法,并结合最上面的交互过程,得到方法调用栈图下图所示:
          image
          我们首先进入到 DefaultBeanDefinitionDocumentReader 里面,可以看到 processBeanDefinition 方法中,调用了 BeanDefinitionParserDelegate 来最终完成这个整个解析过程,得到的结果由 BeanDefinitionHolder 来持有,源码清单如下:
          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));
              }
          }
          
          BeanDefinitionHolder 是 BeanDefinition 对象类的封装类,封装了 BeanDefinition、Bean 的名字和别名,用它来向 IoC 容器注册。而具体的解析过程交由 BeanDefinitionParserDelegate 完成,感兴趣的读者可以继续仔细最终研究。下面我们举个例子来分析一下。
      • 我们先来看一下最常见的 Bean 元素解析:
        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);
            }
            // 这个方法引发对 bean 元素的详细解析
            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;
        }
        
        在这里我们会看到 XML 定义文件常见到的属性元素,如 id、name、aliase 等,把这些元素从 XML 文件转化而来的 element 中取出来,并设置到 BeanDefinitionHolder 中去,这些属性的解析还是比较简单的。对于其他元素配置的解析,如各种 Bean 的属性配置,则为一个较为复杂的过程,由 parseBeanDefinitionElement 方法完成。
        • 以上介绍了对 Bean 元素进行解析的过程。也就是 BeanDefinition 根据 XML 的 <bean> 定义被创建的过程。这个 BeanDefinition 可以看成 <bean> 定义的抽象。这个数据对象中封装的数据大都是与 <bean> 定义相关的,也就是我们在定义 Bean 时看到的那些 Spring 标记,如 init-method、destroy-method 等。这个 BeanDefinition 数据类型是非常重要的,它封装了很多基本数据,这些基本数据都是 IoC 容器需要的。 BeanDefinition 是 IoC 容器中非常核心的数据结构,而通过上述的解析,这些数据已经准备好在 IoC 容器中大显身手了。
        • 下面我们再接着跟踪,进入 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);
                  // 这里对当前的 Bean 元素进行属性分析,并设置描述信息。
                  parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
                  bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
                  // 从名字可以看出,这里是对各种 <bean> 元素的信息进行解析的地方。
                  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 的地方。在这里,我们举一个对 property 进行解析的例子,最终完成对整个 BeanDefinition 载入和解析的过程。这里是指对 Bean 元素下的 property 子元素进行解析。
          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)) {
                      // 进行详细的解析
                      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 的过程。返回的对象对应在 Bean 中定义的 property 属性的解析结果,这个结果会封装到 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 子元素的解析过程,Array、List、Set、Map 等元素都会在这里解析
          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;
              }
          }
          
          property 子元素的解析,最终会生成对应的数据对象,比如 ManagedList、ManagedArray、ManagedSet等,这些 Managed 类是 Spring 的具体的 BeanDefinition 的数据封装。具体的过程读者可以去查看具体的解析过程。从一系列 parse 方法名字可以很清楚的看出是对哪种类型的解析,具体的过程我们就不再查看了。

    这样逐层的解析,我们在 XML 定义的 BeanDefinition 就被整个载入到 IoC 容器中,并在容器中建立了数据映射,即在 IoC 容器创建了对应的数据结构,这些数据结构以 AbstractBeanDefinition 为入口,让 IoC 容器进行索引、查询和操作。但是,重要的依赖注入实际上还没有发生,现在 IoC 容器 BeanDefinition 中存在的还只是一些静态的配置。严格来说,这时候的容器还没有完全起作用,要完全发挥容器的作用,还需要完成数据向容器的注册。

    相关文章

      网友评论

        本文标题:IoC 容器的初始化之 BeanDefinition 的载入和

        本文链接:https://www.haomeiwen.com/subject/dearbxtx.html