Spring 源码阅读-1-xml加载解析

XML加载解析

1、 加载 Bean 定义

1.1 解析XML 处理Document

XmlBeanDefinitionReader#loadBeanDefinitions

/**
 * 加载xml资源,解析xml所有标签,将xml对应的bean封装为BeanDefinition(真实类型为GenericBeanDefinition),并注册
 * 返回加载的BeanDefinition数量
 */
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
   // EncodedResource 增加了encoding以及charset属性
   Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
   if (currentResources == null) {
      currentResources = new HashSet<>(4);
      this.resourcesCurrentlyBeingLoaded.set(currentResources);
   }
    // 将当前加载的xml记录一下。正在加载
   if (!currentResources.add(encodedResource)) {
      throw new BeanDefinitionStoreException(
            "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
   }
      // 获取配置资源输入文件流对象(xml文件输入流)
      InputStream inputStream = encodedResource.getResource().getInputStream();
      // org.xml.sax.InputSource
      // 封装为 InputSource 为 xml解析做准备
      InputSource inputSource = new InputSource(inputStream);
      if (encodedResource.getEncoding() != null) {
          inputSource.setEncoding(encodedResource.getEncoding());
      }
      // 真正的处理
      return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
	....
   finally {
      currentResources.remove(encodedResource);
      if (currentResources.isEmpty()) {
          // 加载结束删除
         this.resourcesCurrentlyBeingLoaded.remove();
      }
   
}

此方法为加载xml的最上层方法,首先接在xml配置文件,然后将文件封装为InputSource,然后将真正对xml的处理交给doLoadBeanDefinitions方法处理。

XmlBeanDefinitionReader#doLoadBeanDefinitions


/**
 * 将任务进一步拆分
 * 将xml文件解析封装为Document
 * 然后根据Document注册bean信息
 * @param inputSource
 * @param resource
 * @return
 * @throws BeanDefinitionStoreException
 */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
   try {
      // 获取对 XML 文件的验证模式并加载xml文件为document
      Document doc = doLoadDocument(inputSource, resource);
      // 根据返回的 Document 注册 Bean 信息
      return registerBeanDefinitions(doc, resource);
   }
  ...
}

此方法进一步拆分任务,DefaultDocumentLoader#loadDocument 将xml流解析成Document对象,XmlBeanDefinitionReader#registerBeanDefinitions根据Document对象进一步解析,注册bean信息。

XmlBeanDefinitionReader#doLoadDocument

/**
 * 解析XML 
 * 允许使用标准 XML 实体将 XML 片段包含到应用程序上下文定义中,例如将大型 XML 文件拆分为各种模块
 */
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
   // getValidationModeForResource  获取对 XML 文件的验证模式   (1、dtd 2、xsd) 如果未设置将加载流自动判断模式
   // getEntityResolver XML 解析器
   return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
         getValidationModeForResource(resource), isNamespaceAware());
}

XmlBeanDefinitionReader#registerBeanDefinitions中通过DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions在给定的根 元素中注册每个 bean 定义。

protected void doRegisterBeanDefinitions(Element root) {
   ....
   if (this.delegate.isDefaultNamespace(root)) {
      // 处理 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)) {
            if (logger.isInfoEnabled()) {
               logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                     "] not matching: " + getReaderContext().getResource());
            }
            return;
         }
      }
   }
   // 前置处理留给子类处理
   preProcessXml(root);
   // 真正的解析bean定义
   parseBeanDefinitions(root, this.delegate);
   // 后置处理留给子类处理
   postProcessXml(root);
   ....
}

DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

/**
 * 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) {
   // 对beans 处理
   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) {
            // 对 bean处理
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               // 处理 默认的 http //w ww.springframework org/scherna beans
               parseDefaultElement(ele, delegate);
            }
            else {
                // 处理自定义的 比如 tx下的
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

到此,开始根据root(beans)节点循环解析子标签,子标签又分为默认标签以及自定义标签,这两种处理方式截然不同。一下都是在说默认标签,自定义标签单独说明。

到此已完成的任务

  1. 加载xml resource资源,并且封装为EncodedResource(可以设置charset)。
  2. 将xml资源输入流对象封装为InputSource,供DocumentLoader加载并解析为Document对象(需要指定Xml解析器,以及XMl格式为标准模式的哪一种(xsd|dtd))。
  3. 通过Document获取root节点开始解析,在此之前可以通过前置处理器处理(root),在此之后可以通过后置处理器处理(root)。
  4. 循环解析root下的所有子标签,标签分为默认标签以及自定义标签,处理截然不同。默认标签,例如 bean、import等,自定义标签,例如tx等。

1.2 解析默认标签

DefaultBeanDefinitionDocumentReader#parseDefaultElement

/**
 * beans.xsd 默认四种类型   import bean beans alias
 * @param ele
 * @param delegate
 */
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   // import 类型处理
   // 是加上就是递归调用 加载配置文件定义bean方法
   // XMLBeanDefinitionReader.loadBeanDefinitions(resource)
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   // alias 处理
   // 跟bean中name属性处理相同
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   // bean 处理
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   // beans 处理
   // 嵌套一不签到没啥大的区别  循环调用  beans 解析过程
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

此方法对各个默认标签进行不同处理,import与beans实则都是递归调用解析过程,所以主要看alias与bean。

bean标签解析

DefaultBeanDefinitionDocumentReader#processBeanDefinition

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   // 将bean 下的各种 默认属性 等 进行解析 并存放到bdholder对象中
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      // bdholder 不为空的情况下查看 是否还有 自定义 属性 并解析
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      // 解析完成后 bdHolder 中会有这个bean标签的全部信息
      try {
         // 然后在委托 BeanDefinitionReaderUtils.registerBeanDefinition 进行注册
         // 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);
      }
      // 通知此bean已经注册完成
      // 为了以后扩展的目前没有实现
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

此方法中BeanDefinitionParserDelegate.parseBeanDefinitionElement对默认标签进行解析,并将解析后的信息保存到BeanDefinitionHolder

BeanDefinitionParserDelegate#parseBeanDefinitionElement

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
   // 解析id
   String id = ele.getAttribute(ID_ATTRIBUTE);
   // 解析 name
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
   // 分割 name
   List<String> aliases = new ArrayList<>();
   if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }
   String beanName = id;
   // id 为null 使用 name 的第一个
   if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
   	  ...
   }
   // 检查beanName的在bean容器中的唯一性
   if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
   }
   // 进一步解析bean的其他所有属性  就是一个bean中的所有属性和元素解析成javaBean,即 AbstractBeanDefinition
   // xml中的bean有什么  AbstractBeanDefinition 类 就有什么
   AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {
      if (!StringUtils.hasText(beanName)) {
           ...
            // 不存在beanName 根绝Spring  提供的命名规则为当前bean生成 beanname
            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);
               }
            }
           ...
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }
   return null;
}

此方法中对bean标签的属性(只是解析id以及name,其他的也是在下面的方法中解析)进行解析,对子标签的解析交给下层进行处理(BeanDefinitionParserDelegate#parseBeanDefinitionElement),对bean下的自定义标签的解析单独处理。

BeanDefinitionParserDelegate#parseBeanDefinitionElement

/**
 * Parse the bean definition itself, without regard to name or aliases. May return
 * {@code null} if problems occurred during the parsing of the bean definition.
 */
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {
   // 一个集合(LinkedList ) 将正在解析的beanname记录
   this.parseState.push(new BeanEntry(beanName));
   // 解析 class
   String className = null;
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
   }
   // 解析 parent
   String parent = null;
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }
	...
      // 创建用于承载属性AbstractBeanDefinition类型的GenericBeanDefinition
      // BeanDefinition 是配置文件<bean>元素标签在容器中的内部表示形式
      // <bean>元素标签拥有
      //class scope lazy-init 等配置属性, BeanDefinition 则提供了相应的 beanClass scope lazyInit
      //属性, BeanDefinition <bean>中的属性是 一对应的
      // Spring 通过 BeanDefinition 将配置文件中的<bea >配置信息转换为容器的内部表示,并将
      //这些 BeanDefinition 注册到 BeanDefinitionReistry中。 Spring 容器的 BeanDefinitionRegistrγ 就像
      //Spring 配置信息的内存数据库,主要是以 map 的形式保存,后续操作直接从 BeanDefinition Registry 中读取配置信息
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);
      // 硬编码解析默认 bean的各种默认属性
      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      // 一下全部是子元素的 解析
      // 提取 description
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
      // 解析 meta  元数据 子元素
      // 取出全部meta子元素, 将key-value 封装成 BeanMetadataAttribute对象(还包括)保存到 BeanMetadataAttributeAccessor中
      // AbstractBeanDefinition 集成了 BeanMetadataAttributeAccessor
      parseMetaElements(ele, bd);
      // 解析 lookup-method
      // 抽象方法 返回 指定的bean  <lookup-method name="getBean" bean="bean">  getBean 为抽象方法
      parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      // 解析 replaced-method
      // 与 lookup-method 的区别是  lookup-method自定义 返回的bean  ,replaced-method可以将方法的逻辑进行替换
      // 都会 封装成 MethodOverride  存放到  bd的methodOverrides中
      parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
      // 解析 构造函数参数
      parseConstructorArgElements(ele, bd);
      // 解析property子元素
      parsePropertyElements(ele, bd);
      // 解析 qualifier 子元素   作用指定beanName 消除歧义
      parseQualifierElements(ele, bd);
      bd.setResource(this.readerContext.getResource());
      bd.setSource(extractSource(ele));

      return bd;
	...
   return null;
}

此方法首先解析bean标签的class以及parent,然后创建创建默认的AbstractBeanDefinition,然后通过BeanDefinitionParserDelegate#parseBeanDefinitionAttributes解析bean的各种默认属性,然后在此方法中解析其他的子标签(例如lookup-method、property、constructor等)。

BeanDefinitionParserDelegate#parseBeanDefinitionAttributes

/**
 * 将给定 bean 元素的属性应用于给定 bean 定义
 * Apply the attributes of the given bean element to the given bean * definition.
 * @param ele bean declaration element
 * @param beanName bean name
 * @param containingBean containing bean definition
 * @return a bean definition initialized according to the bean element attributes
 */
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
      @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

   // 解析 singleton 使用singleton会 提示错误
   if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
      error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
   }
   // 解析 scope
   else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
      bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
   }
   // 在嵌入 beanDifinition 情况下且没有单独指定 scope 属性则使用父类默认的属性
   else if (containingBean != null) {
      // Take default from containing bean in case of an inner bean definition.
      bd.setScope(containingBean.getScope());
   }
   // 解析 abstract
   if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
      bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
   }
   // 解析 lazy-init
   String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
   if (isDefaultValue(lazyInit)) {
      lazyInit = this.defaults.getLazyInit();
   }
   // 非true字符串或空都将是false
   bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
   // 解析 autowire
   String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
   bd.setAutowireMode(getAutowireMode(autowire));
   // 解析 depends-on
   if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
      String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
      bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
   }
   // 解析autowire-candidate属性
   String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
   if (isDefaultValue(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));
   }
   // 解析 primary 属性
   if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
      bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
   }
   // 解析 init-method
   if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
      String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
      bd.setInitMethodName(initMethodName);
   }
   else if (this.defaults.getInitMethod() != null) {
      bd.setInitMethodName(this.defaults.getInitMethod());
      bd.setEnforceInitMethod(false);
   }
   // 解析 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);
   }
   // 解析 factory-method
   if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
      bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
   }
   // 解析factory-bean
   if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
      bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
   }
   return bd;
}

至此一个bean的默认标签解析工作就完成了,xml中bean标签的所有信息都被封装到了AbstractBeanDefinition对象中。

bean下的自定义标签的解析将单独说明

DefaultBeanDefinitionDocumentReader#processBeanDefinition中解析完 bean的默认标签以及自定义标签后,需要将保存着bean定义信息的对象(BeanDefinitionHolder),通过DefaultListableBeanFactory#registerBeanDefinition方法注册到Spring容器中。

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {
    ...
   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         //  注册前的最后一次校验,这里的校验不同于之前XML文件校验,
         //  主要是对 AbstractBeanDefinition 中 methodOverrides 校验
         //  校验 methodOverrides 是否与工厂方法并存或者 methodOverrides 对应的方法根本不存在
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
    ...
   }
   // 线程安全的map 所以这里不需要在使用 synchronized
   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   // 通过 beanName 查询的 bean 已经存在
   if (existingDefinition != null) {
      // 一系列判断
      // 是否允许Bean定义重写 检查是否允许覆盖
      // 如果对应的 BeanName 已经注册且在配置中配置了 bean 不允许被覆盖,则抛出异常
      // 当前要保存的是否和取出来的是一个对象
      // 注册beanDefinition
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
       // bean是否被标记为已创建
       // 需要全复制
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // Still in startup registration phase
         this.beanDefinitionMap.put(beanName, beanDefinition);
         // 记录 bean 名称
         this.beanDefinitionNames.add(beanName);
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }
	// bean被新的定义覆盖了   或者是   单例
   if (existingDefinition != null || containsSingleton(beanName)) {
      // 重置给定 bean 的所有 bean 定义缓存,包括从它派生的 bean 缓存
      resetBeanDefinition(beanName);
   }
   else if (isConfigurationFrozen()) {
      clearByTypeCache();
   }
}

至此bean的解析,注册全部完成

import 除去解析特定的几个属性外就是递归调用beans解析过程。

beans 下包含 beans的情况也是递归调用beans的解析过程。

aliase 主要是解析默认属性,并记录别名与beanname的关联关系。

已完成的任务:

  1. root下的不同子标签,分别进行解析(import bean beans alias)

  2. 解析bean标签所有默认属性(class、id等)

  3. 解析bean标签所有子标签(property等)

  4. 解析bean下所有自定义标签

  5. 将承载xml中bean标签全部信息的AbstractBeanDefinition对象注册到Spring 容器(其实就是map,保存到里面)

    注意 自定义标签的解析未说明,单独说明。

                                                                                                                       ---- **Cover 《Spring 源码深度解析》**
    
posted @ 2021-11-11 12:09  余小叙  阅读(64)  评论(0编辑  收藏  举报