Spring 啓動記錄(8)

Spring DefaultBeanDefinitionDocumentReader註冊BeanDifinitionjava

一、node

spring

此圖繼承圖,只是簡單一個接口一個實現類express

 

/*
 * Copyright 2002-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.xml;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.LinkedHashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

/**
 * Default implementation of the {@link BeanDefinitionDocumentReader} interface that
 * reads bean definitions according to the "spring-beans" DTD and XSD format
 * (Spring's default XML bean definition format).
 *
 * <p>The structure, elements, and attribute names of the required XML document
 * are hard-coded in this class. (Of course a transform could be run if necessary
 * to produce this format). {@code <beans>} does not need to be the root
 * element of the XML document: this class will parse all bean definition elements
 * in the XML file, regardless of the actual root element.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @author Erik Wiersma
 * @since 18.12.2003
 */
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

   public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;

   public static final String NESTED_BEANS_ELEMENT = "beans";

   public static final String ALIAS_ELEMENT = "alias";

   public static final String NAME_ATTRIBUTE = "name";

   public static final String ALIAS_ATTRIBUTE = "alias";

   public static final String IMPORT_ELEMENT = "import";

   public static final String RESOURCE_ATTRIBUTE = "resource";

   public static final String PROFILE_ATTRIBUTE = "profile";


   protected final Log logger = LogFactory.getLog(getClass());

   private XmlReaderContext readerContext;

   private BeanDefinitionParserDelegate delegate;


   /**
    * This implementation parses bean definitions according to the "spring-beans" XSD
    * (or DTD, historically).
    * <p>Opens a DOM Document; then initializes the default settings
    * specified at the {@code <beans/>} level; then parses the contained bean definitions.
    */
   @Override
   public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
      this.readerContext = readerContext;
      logger.debug("Loading bean definitions");
      Element root = doc.getDocumentElement();
      doRegisterBeanDefinitions(root);
   }

   /**
    * Return the descriptor for the XML resource that this parser works on.
    */
   protected final XmlReaderContext getReaderContext() {
      return this.readerContext;
   }

   /**
    * Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the
    * source metadata from the supplied {@link Element}.
    */
   protected Object extractSource(Element ele) {
      return getReaderContext().extractSource(ele);
   }


   /**
    * Register each bean definition within the given root {@code <beans/>} element.
    * 註冊BeanDifinition的方法
    */
   protected void doRegisterBeanDefinitions(Element root) {
      // Any nested <beans> elements will cause recursion in this method. In
      // order to propagate and preserve <beans> default-* attributes correctly,
      // keep track of the current (parent) delegate, which may be null. Create
      // the new (child) delegate with a reference to the parent for fallback purposes,
      // then ultimately reset this.delegate back to its original (parent) reference.
      // this behavior emulates a stack of delegates without actually necessitating one.
      BeanDefinitionParserDelegate parent = this.delegate;
      //調用了BeanDefinitionParserDelegate這個類去解析
      this.delegate = createDelegate(getReaderContext(), root, parent);
      
      if (this.delegate.isDefaultNamespace(root)) {
        //判讀xml的xmlns是否等於http://www.springframework.org/schema/beans     
        //判斷是否有profile屬性,屬於哪一個環境
         String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
         if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                  profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
               return;
            }
         }
      }

      preProcessXml(root);
      parseBeanDefinitions(root, this.delegate);
      postProcessXml(root);

      this.delegate = parent;
   }
  //建立BeanDefinitionParserDelegate
   protected BeanDefinitionParserDelegate createDelegate(
         XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {

      BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
      //初始化信息
      delegate.initDefaults(root, parentDelegate);
public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
   populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
   //通知註冊的監聽器,(spring的beans對應的BeanDefinition初始化完成已完成此時)
   this.readerContext.fireDefaultsRegistered(this.defaults);
}
     
BeanDefinitionParserDelegate的方法
public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
   populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
   this.readerContext.fireDefaultsRegistered(this.defaults);
}
/**
 * Populate the given DocumentDefaultsDefinition instance with the default lazy-init,
 * autowire, dependency check settings, init-method, destroy-method and merge settings.
 * Support nested 'beans' element use cases by falling back to <literal>parentDefaults</literal>
 * in case the defaults are not explicitly set locally.
 * @param defaults the defaults to populate
 * @param parentDefaults the parent BeanDefinitionParserDelegate (if any) defaults to fall back to
 * @param root the root element of the current bean definition document (or nested beans element)
  給每一個xml的表情<beans>lazy-init, * autowire, dependency check settings, init-method, destroy-method and merge默認值
public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";

public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge";

public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";

public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";

public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = "default-autowire-candidates";

public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method";

public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method";
*/
protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
   String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
   if (DEFAULT_VALUE(default).equals(lazyInit)) {
      // Potentially inherited from outer <beans> sections, otherwise falling back to false.
      //若是有父類的解析器,則讀取父類的配置,沒有就是false
      lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE(false));
   }
   defaults.setLazyInit(lazyInit);

   String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
   if (DEFAULT_VALUE.equals(merge)) {
      // Potentially inherited from outer <beans> sections, otherwise falling back to false.
      merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
   }
   //設置merge配置
   defaults.setMerge(merge);
   
   String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
   if (DEFAULT_VALUE.equals(autowire)) {
      // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
      autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
   }
   defaults.setAutowire(autowire);

   // Don't fall back to parentDefaults for dependency-check as it's no longer supported in
   // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
   //此處對與dependencyCheck配置從spring3.0開始再也不支持父類解析器配置屬性繼承只讀取子類的配置
   defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));

   if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
      defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
   }
   else if (parentDefaults != null) {
      defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
   }

   if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
      defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
   }
   else if (parentDefaults != null) {
      defaults.setInitMethod(parentDefaults.getInitMethod());
   }

   if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
      defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
   }
   else if (parentDefaults != null) {
      defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
   }

   defaults.setSource(this.readerContext.extractSource(root));
}

      return delegate;
   }

   /**
    * Parse the elements at the root level in the document:
    * "import", "alias", "bean".
    * @param root the DOM root element of the document
    */
   protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
      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)) {
                  parseDefaultElement(ele, delegate);
               }
               else {
                  delegate.parseCustomElement(ele);
               }
            }
         }
      }
      else {
         delegate.parseCustomElement(root);
      }
   }

   private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
      if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
         importBeanDefinitionResource(ele);
      }
      else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
         processAliasRegistration(ele);
      }
      else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
         processBeanDefinition(ele, delegate);
      }
      else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
         // recurse
         doRegisterBeanDefinitions(ele);
      }
   }

   /**
    * Parse an "import" element and load the bean definitions
    * from the given resource into the bean factory.
    */
   protected void importBeanDefinitionResource(Element ele) {
      String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
      if (!StringUtils.hasText(location)) {
         getReaderContext().error("Resource location must not be empty", ele);
         return;
      }

      // Resolve system properties: e.g. "${user.dir}"
      location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

      Set<Resource> actualResources = new LinkedHashSet<Resource>(4);

      // Discover whether the location is an absolute or relative URI
      boolean absoluteLocation = false;
      try {
         absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
      }
      catch (URISyntaxException ex) {
         // cannot convert to an URI, considering the location relative
         // unless it is the well-known Spring prefix "classpath*:"
      }

      // Absolute or relative?
      if (absoluteLocation) {
         try {
            int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
            if (logger.isDebugEnabled()) {
               logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
            }
         }
         catch (BeanDefinitionStoreException ex) {
            getReaderContext().error(
                  "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
         }
      }
      else {
         // No URL -> considering resource location as relative to the current file.
         try {
            int importCount;
            Resource relativeResource = getReaderContext().getResource().createRelative(location);
            if (relativeResource.exists()) {
               importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
               actualResources.add(relativeResource);
            }
            else {
               String baseLocation = getReaderContext().getResource().getURL().toString();
               importCount = getReaderContext().getReader().loadBeanDefinitions(
                     StringUtils.applyRelativePath(baseLocation, location), actualResources);
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
            }
         }
         catch (IOException ex) {
            getReaderContext().error("Failed to resolve current resource location", ele, ex);
         }
         catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
                  ele, ex);
         }
      }
      Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
      getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
   }

   /**
    * Process the given alias element, registering the alias with the registry.
    */
   protected void processAliasRegistration(Element ele) {
      String name = ele.getAttribute(NAME_ATTRIBUTE);
      String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
      boolean valid = true;
      if (!StringUtils.hasText(name)) {
         getReaderContext().error("Name must not be empty", ele);
         valid = false;
      }
      if (!StringUtils.hasText(alias)) {
         getReaderContext().error("Alias must not be empty", ele);
         valid = false;
      }
      if (valid) {
         try {
            getReaderContext().getRegistry().registerAlias(name, alias);
         }
         catch (Exception ex) {
            getReaderContext().error("Failed to register alias '" + alias +
                  "' for bean with name '" + name + "'", ele, ex);
         }
         getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
      }
   }

   /**
    * Process the given bean element, parsing the bean definition
    * and registering it with the registry.
    */
   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));
      }
   }


   /**
    * Allow the XML to be extensible by processing any custom element types first,
    * before we start to process the bean definitions. This method is a natural
    * extension point for any other custom pre-processing of the XML.
    * <p>The default implementation is empty. Subclasses can override this method to
    * convert custom elements into standard Spring bean definitions, for example.
    * Implementors have access to the parser's bean definition reader and the
    * underlying XML resource, through the corresponding accessors.
    * @see #getReaderContext()
    */
   protected void preProcessXml(Element root) {
   }

   /**
    * Allow the XML to be extensible by processing any custom element types last,
    * after we finished processing the bean definitions. This method is a natural
    * extension point for any other custom post-processing of the XML.
    * <p>The default implementation is empty. Subclasses can override this method to
    * convert custom elements into standard Spring bean definitions, for example.
    * Implementors have access to the parser's bean definition reader and the
    * underlying XML resource, through the corresponding accessors.
    * @see #getReaderContext()
    */
   protected void postProcessXml(Element root) {
   }

}

相關文章
相關標籤/搜索