Spring IOC源码:obtainFreshBeanFactory 详解(中)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring IOC源码:obtainFreshBeanFactory 详解(中)

文章目录

Spring源码系列:

前言

正文

方法1:processBeanDefinition

方法2:parseBeanDefinitionElement

方法3:parseBeanDefinitionElement

方法4:parseBeanDefinitionAttributes

方法5:parseConstructorArgElements

方法6:parseConstructorArgElement

方法7:parsePropertyValue

方法8:parsePropertySubElement

方法9:parsePropertyElements

方法10:registerBeanDefinition

方法11:registerBeanDefinition

方法12:resetBeanDefinition

方法13:resetBeanDefinition

总结

Spring源码系列:

Spring IOC源码:简单易懂的Spring IOC 思路介绍

Spring IOC源码:核心流程介绍

Spring IOC源码:ApplicationContext刷新前准备工作

Spring IOC源码:obtainFreshBeanFactory 详解(上)

Spring IOC源码:obtainFreshBeanFactory 详解(中)

Spring IOC源码:obtainFreshBeanFactory 详解(下)

Spring IOC源码:<context:component-scan>源码详解

Spring IOC源码:invokeBeanFactoryPostProcessors 后置处理器详解

Spring IOC源码:registerBeanPostProcessors 详解

Spring IOC源码:实例化前的准备工作

Spring IOC源码:finishBeanFactoryInitialization详解

Spring IoC源码:getBean 详解

Spring IoC源码:createBean( 上)

Spring IoC源码:createBean( 中)

Spring IoC源码:createBean( 下)

Spring IoC源码:finishRefresh 完成刷新详解

前言

上篇文章我们介绍了prepareRefresh方法,配置解析前的准备工作,和obtainFreshBeanFactory方法,配置解析核心处理方法。我们讲解到了parseBeanDefinitions方法,该方法会根据命名空间去选择对应的逻辑处理。本章节介绍默认命名空间的处理逻辑parseDefaultElement(ele, delegate);

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)) {
            //默认命名空间节点的处理,例如: <bean id="test" class="" />
            parseDefaultElement(ele, delegate);
          }
          else {
            // 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/>
            delegate.parseCustomElement(ele);
          }
        }
      }
    }
    else {
      //非默认命名空间走其它逻辑
      delegate.parseCustomElement(root);
    }
  }

正文

进入parseDefaultElement(ele, delegate)方法,我们可以看到有四种类型的判断,import、alias、bean、beans。这里获取一级节点,判断节点类型选择对应的解析方法。几种类型的解析都是比较类似的,这里我们使用的bean,学会的bean去看其它都是大同小异,而beans节点其实是重新调用一遍doRegisterBeanDefinitions方法,进行子节点的遍历解析工作。bean节点解析见方法1

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

xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean name="teacher" class="service.impl.Teacher">
    <property name="name" value="张三"></property>
    <property name="age" value="30"></property>
  </bean>
</beans>

方法1:processBeanDefinition

  protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //通过解析器进行解析,解析出类名、class、id、父类、属性依赖等
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
      //bean解析器只能解析一些默认的配置,这里判断是否有自定义的属性或子节点需要进一步解析并封装,
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
        // 将bdHolder 注册到上下文缓存中beanDefinitionNames、beanDefinitionMap、aliasMap
        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));
    }
  }

1、delegate.parseBeanDefinitionElement(ele)方法:见方法2详解


2、delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)方法:

这个方法主要是考虑到bean节点中的属性或者子节点包含了自定义内容,默认的解析器没办法解析到,所以需要做下后置处理,判断是否有自定义的,通过自定义获取命名空间,通过命名空间加载解析器进行处理,将处理好的值封装到步骤1解析出来的BeanDefinitionHolder 中。例如下面的“zhudachang”属性和 < myBean > 子节点。这节我们要研究默认命名空间,所以这里不做深入,等后面讲解了自定义的内容后,再来看这块就比较简单了。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean name="teacher" class="service.impl.Teacher" zhudachang="">
    <property name="name" value="张三"></property>
    <property name="age" value="30"></property>
    <myBean></myBean>
  </bean>
</beans>

方法2:parseBeanDefinitionElement

  public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
  }
  public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    //获取id和name属性值
    String id = ele.getAttribute(ID_ATTRIBUTE);
    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));
    }
    //如果beanName为空,则以aliases中的第一条数据作为beanName名称,并移除。
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isTraceEnabled()) {
        logger.trace("No XML 'id' specified - using '" + beanName +
            "' as bean name and " + aliases + " as aliases");
      }
    }
    //查询一下该beanName 名称是否作为第一个被使用了
    if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
    }
    //解析节点并封装成GenericBeanDefinition
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
      if (!StringUtils.hasText(beanName)) {
        try {
          if (containingBean != null) {
            //默认规则生成,获取class名称,如果class名称为空,则看beanDefinition的父类或FactoryBean的名称+固定后最作为Bean名称,如果是内部的Bean则按另一个逻辑生成;
            beanName = BeanDefinitionReaderUtils.generateBeanName(
                beanDefinition, this.readerContext.getRegistry(), true);
          }
          else {
            beanName = this.readerContext.generateBeanName(beanDefinition);
            // Register an alias for the plain bean class name, if still possible,
            // if the generator returned the class name plus a suffix.
            // This is expected for Spring 1.2/2.0 backwards compatibility.
            String beanClassName = beanDefinition.getBeanClassName();
            //如果是默认规则生成的,则加入别名集合中
            if (beanClassName != null &&
                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
              aliases.add(beanClassName);
            }
          }
          if (logger.isTraceEnabled()) {
            logger.trace("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);
      //将beanDefinition跟类名、别名封装成 BeanDefinitionHolder
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }
    return null;
  }

1、beanName的获取规则,如果bean节点配置了id属性,则以id作为beanName。如果没有id,但是有配置name属性,则解析名称中是否含有多个,如果有多个则将第一个作为beanName,其余的作为别名,加入aliases集合中。

例如:

  <bean name="ZHU,DA,CHANG" class="service.impl.Teacher">
    <property name="name" value="张三"></property>
    <property name="age" value="30"></property>
  </bean>

这里的beanName为"ZHU",别名为“DA”,“CHANG"

  <bean id="teacher" name="zhudachang" class="service.impl.Teacher">
    <property name="name" value="张三"></property>
    <property name="age" value="30"></property>
  </bean>

这里的beanName为"teacher",别名为“zhudachang”

2、parseBeanDefinitionElement(ele, beanName, containingBean)方法:见方法3详解

方法3:parseBeanDefinitionElement

  public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {
    //将beanName封装成BeanEntry对象
    this.parseState.push(new BeanEntry(beanName));
    //获取class类属性
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    //获取父类属性
    String parent = null;
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }
    try {
      //创建GenericBeanDefinition,并设置父类名称,通过className获取class并设置
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);
      //解析设置各种属性
      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      //设置description信息
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
      //解析元数据
      parseMetaElements(ele, bd);
      //设置LookupOverride
      parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      //设置ReplacedMethod
      parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
      //解析设置构造函数节点
      parseConstructorArgElements(ele, bd);
      //解析设置子节点属性
      parsePropertyElements(ele, bd);
      //解析设置Qualifier
      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;
  }

1、parseBeanDefinitionAttributes(ele, beanName, containingBean, bd)方法,见方法4详解

2、parseLookupOverrideSubElements(ele, bd.getMethodOverrides())

该方法主要解析子节点中的< lookup-method >标签,该标签处理Bean中属性为原型模式,也就是每次获取该属性时都会新创建一个对象。

如:Teacher类中声明了Address属性,而我们的Address是prototype原型模式,也就是每次获取该值都会创建一个新的对象,而Teacher是一个单例,获取该类时,每次都从缓存中获取,导致类中的Adress也是一个单例,这里就是为后续处理该问题作准备。后续文章会专门讲解这个的用法。

  <bean name="address" class="service.Address" scope="prototype"></bean>
  <bean id="teacher" name="teacher" class="service.impl.Teacher" >
    <lookup-method name="getAddress" bean="address"></lookup-method>
  </bean>

3、parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

  <bean name="address" class="service.Address" scope="prototype"></bean>
  <bean id="teacher" name="teacher" class="service.impl.Teacher" >
    <replaced-method name="getAddress" replacer="addressMethodReplacer"></replaced-method>
  </bean>

4、parseConstructorArgElements(ele, bd)方法,见方法5详解

5、parsePropertyElements(ele, bd)方法见方法9详解

方法4:parseBeanDefinitionAttributes

    // 解析设置singleton属性
    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        // singleton属性以被scope属性代替
        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));
    }
    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属性, 默认为false
    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (DEFAULT_VALUE.equals(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
    // 解析设置autowire属性
    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));
    // 解析设置dependency-check属性
    String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
    bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
    // 解析设置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 ("".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));
    }
    // 解析设置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);
        if (!"".equals(initMethodName)) {
            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;
}

方法5:parseConstructorArgElements

    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
      Node node = nl.item(i);
      if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
        parseConstructorArgElement((Element) node, bd);
      }
    }


这里遍历子节点中的< constructor-arg >标签,对其属性进行解析封装,parseConstructorArgElement((Element) node, bd)方法见方法6详解

  <bean id="address"  class="service.Address" ></bean>
  <bean  id="teacher" name="teacher" class="service.impl.Teacher">
    <constructor-arg index="0" value="zhangsan"></constructor-arg>
    <constructor-arg index="1" value="13"></constructor-arg>
    <constructor-arg index="2" ref="address"></constructor-arg>
    <constructor-arg index="3" >
      <list>
        <value>zhudachang1</value>
        <value>zhudachang2</value>
        <value>zhudachang3</value>
      </list>
    </constructor-arg>
  </bean>

方法6:parseConstructorArgElement

public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
    //获取index属性
    String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
    //获取type属性
    String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
    //获取name属性
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    if (StringUtils.hasLength(indexAttr)) {
      //如果有index属性
      try {
        int index = Integer.parseInt(indexAttr);
        if (index < 0) {
          error("'index' cannot be lower than 0", ele);
        }
        else {
          try {
            //校验该index是否>=0,否则抛异常
            this.parseState.push(new ConstructorArgumentEntry(index));
            //获取其值,可能是通过 value 属性、ref 属性、list 属性等
            Object value = parsePropertyValue(ele, bd, null);
            //封装成ConstructorArgumentValues对象
            ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
            if (StringUtils.hasLength(typeAttr)) {
            //设置type值
              valueHolder.setType(typeAttr);
            }
            if (StringUtils.hasLength(nameAttr)) {
            //设置name值
              valueHolder.setName(nameAttr);
            }
            valueHolder.setSource(extractSource(ele));
            if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
              error("Ambiguous constructor-arg entries for index " + index, ele);
            }
            else {
              //添加下标及其对应的值
              bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
            }
          }
          finally {
            this.parseState.pop();
          }
        }
      }
      catch (NumberFormatException ex) {
        error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
      }
    }
    else {
      try {
        //如果没有index,此时不做校验
        this.parseState.push(new ConstructorArgumentEntry());
        //获取当前设置值,可能是通过 value 属性、ref 属性、list 属性等
        Object value = parsePropertyValue(ele, bd, null);
        //同上面步骤一样
        ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
        if (StringUtils.hasLength(typeAttr)) {
          valueHolder.setType(typeAttr);
        }
        if (StringUtils.hasLength(nameAttr)) {
          valueHolder.setName(nameAttr);
        }
        valueHolder.setSource(extractSource(ele));
        //由于没有下标,这里直接添加集合中
        bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
      }
      finally {
        this.parseState.pop();
      }
    }
  }

parsePropertyValue(ele, bd, null)方法,会解析出当前节点对应的引用类型值,见方法7详解

方法7:parsePropertyValue

public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
    String elementName = (propertyName != null ?
        "<property> element for property '" + propertyName + "'" :
        "<constructor-arg> element");
    //获取该节点下的子节点
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    //如果是List类型,则有子节点。这里会对子节点进行校验
    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);
    //这里不允许有value跟ref共存或者跟有子节点的共存 如list
    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) {
      //获取属性值并将该属性值封装成RuntimeBeanReference 对象
      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) {
      //如果有value值,则封装成TypedStringValue 
      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;
    }
  }

方法8:parsePropertySubElement

public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
    //判断节点标签是否是默认命名空间,不是则走自定义逻辑
    if (!isDefaultNamespace(ele)) {
      return parseNestedCustomElement(ele, bd);
    }
    else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
      //如果是Bean标签,则进行解析,并封装成BeanDefinitionHolder 
      BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
      if (nestedBd != null) {
        //判断该节点是否有自定义标签,有则调用自定义逻辑处理,补充新的解析内容进来
        nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
      }
      return nestedBd;
    }
    else if (nodeNameEquals(ele, REF_ELEMENT)) {
      // 如果是ref,引用其它Bean,获取引用的beanName名称
      String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
      boolean toParent = false;
      if (!StringUtils.hasLength(refName)) {
        // 获取父类beanName
        refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
        toParent = true;
        if (!StringUtils.hasLength(refName)) {
          error("'bean' 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 
      RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
      ref.setSource(extractSource(ele));
      return ref;
    }
    //解析idref节点
    else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
      return parseIdRefElement(ele);
    }
    //解析value
    else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
      return parseValueElement(ele, defaultValueType);
    }
    //解析null
    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;
    }
    //解析Array数组
    else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
      return parseArrayElement(ele, bd);
    }
    //解析List集合
    else if (nodeNameEquals(ele, LIST_ELEMENT)) {
      return parseListElement(ele, bd);
    }
    //解析Set集合
    else if (nodeNameEquals(ele, SET_ELEMENT)) {
      return parseSetElement(ele, bd);
    }
    //解析Map集合
    else if (nodeNameEquals(ele, MAP_ELEMENT)) {
      return parseMapElement(ele, bd);
    }
    //解析props
    else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
      return parsePropsElement(ele);
    }
    else {
      error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
      return null;
    }
  }

1、list节点的解析,获取该节点下的子节点,遍历调用parsePropertySubElement,并将每个子节点添加至Collection中。

2、其它集合Map、Set、Array等的解析过程也跟list类似。

方法9:parsePropertyElements

以上我们介绍了< constructor-arg >标签的解析过程,下面来看下

  public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
      Node node = nl.item(i);
      //如果是默认命名空间标签且是property属性的话,进行解析
      if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
        parsePropertyElement((Element) node, bd);
      }
    }
  }
public void parsePropertyElement(Element ele, BeanDefinition bd) {
    //获取name属性值
    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));
    try {
      if (bd.getPropertyValues().contains(propertyName)) {
        error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
        return;
      }
      //解析获取其值,该方法在前面的解析中有讲解过,这里不做讲解
      Object val = parsePropertyValue(ele, bd, propertyName);
      //根据名称、对象值封装成PropertyValue 
      PropertyValue pv = new PropertyValue(propertyName, val);
      parseMetaElements(ele, pv);
      pv.setSource(extractSource(ele));
      bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {
      this.parseState.pop();
    }
  }

xml配置案例如下:

  <bean id="address"  class="service.Address" scope="prototype"></bean>
  <bean id="teacher" class="service.impl.Teacher">
    <property name="name" value="zhudachang"></property>
    <property name="age" value="11"></property>
    <property name="address" ref="address"></property>
  </bean>


到这里我们的解析工作就完成了,下面回到方法1中,解析后需要将BeanDefinition注册到上下文缓存中,见方法10详解

方法10:registerBeanDefinition

  public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {
    // 获取beanName名称
    String beanName = definitionHolder.getBeanName();
    //注册到缓存中
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    //获取别名集合,注册到上下文的别名缓存中
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
      for (String alias : aliases) {
        registry.registerAlias(beanName, alias);
      }
    }
  }

1、我们看到传进来的是BeanDefinitionRegistry 注册器,我们可以把它当成管理上下文的工具类吧,使用它可以操作上下文的部分增删改查工作

2、registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())方法,见方法11详解

3、registry.registerAlias(beanName, alias)方法,见方法13详解

方法11:registerBeanDefinition

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");
    //如果是AbstractBeanDefinition,则校验
    if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
        ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
            "Validation of bean definition failed", ex);
      }
    }
    //判断缓存中是否存在了该beanName的BeanDefinition 
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
        throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
        // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
        if (logger.isInfoEnabled()) {
          logger.info("Overriding user-defined bean definition for bean '" + beanName +
              "' with a framework-generated bean definition: replacing [" +
              existingDefinition + "] with [" + beanDefinition + "]");
        }
      }
      else if (!beanDefinition.equals(existingDefinition)) {
        if (logger.isDebugEnabled()) {
          logger.debug("Overriding bean definition for bean '" + beanName +
              "' with a different definition: replacing [" + existingDefinition +
              "] with [" + beanDefinition + "]");
        }
      }
      else {
        if (logger.isTraceEnabled()) {
          logger.trace("Overriding bean definition for bean '" + beanName +
              "' with an equivalent definition: replacing [" + existingDefinition +
              "] with [" + beanDefinition + "]");
        }
      }
      //加入缓存中,进行覆盖
      this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
      //检查下当前bean工厂是否开始创建工作,这里是为了加锁
      if (hasBeanCreationStarted()) {
        // Cannot modify startup-time collection elements anymore (for stable iteration)
        synchronized (this.beanDefinitionMap) {
          //将当前beanDefinition放入缓存中
          this.beanDefinitionMap.put(beanName, beanDefinition);
          //统计下数量
          List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
          updatedDefinitions.addAll(this.beanDefinitionNames);
          updatedDefinitions.add(beanName);
          this.beanDefinitionNames = updatedDefinitions;
          removeManualSingletonName(beanName);
        }
      }
      else {
        // 将当前beanDefinition放入缓存中
        this.beanDefinitionMap.put(beanName, beanDefinition);
        //将beanName加入缓存中
        this.beanDefinitionNames.add(beanName);
        removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
    }
    //如果Bean存在于缓存中,并且的单例的,这里需要重置
    if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
    }
  }

1、((AbstractBeanDefinition) beanDefinition).validate();

该方法用于校验节点中不能同时存在factory-method属性和子节点< lookup-method >、< replaced-method >。这个if语句是为了确保,上述两者不能共存,否则就会报错。这是因为,如果给一个 Bean 配置了工厂方法,那么它会由工厂方法来创建,而不是 Spring 默认的方式创建,这种情况下无法进行方法的覆盖。因此,这里的判断是为了确保配置信息没有出现冲突。

  public void validate() throws BeanDefinitionValidationException {
    if (hasMethodOverrides() && getFactoryMethodName() != null) {
      throw new BeanDefinitionValidationException(
          "Cannot combine factory method with container-generated method overrides: " +
          "the factory method must create the concrete bean instance.");
    }
    if (hasBeanClass()) {
      prepareMethodOverrides();
    }
  }

2、resetBeanDefinition(beanName)方法,见方法12详解

方法12:resetBeanDefinition

protected void resetBeanDefinition(String beanName) {
    // 从合并的MergedBeanDefinition缓存中移除
    clearMergedBeanDefinition(beanName);
    //这里移除了很多处缓存,如IOC三级缓存等
    destroySingleton(beanName);
    // 通知后置处理器进行重置处理
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
      if (processor instanceof MergedBeanDefinitionPostProcessor) {
        ((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);
      }
    }
    for (String bdName : this.beanDefinitionNames) {
      if (!beanName.equals(bdName)) {
        BeanDefinition bd = this.beanDefinitionMap.get(bdName);
        //当前遍历的BeanDefinition的parentName为beanName,则递归调用resetBeanDefinition进行重置
        if (bd != null && beanName.equals(bd.getParentName())) {
          resetBeanDefinition(bdName);
        }
      }
    }
  }

方法13:resetBeanDefinition

public void registerAlias(String name, String alias) {
    Assert.hasText(name, "'name' must not be empty");
    Assert.hasText(alias, "'alias' must not be empty");
    synchronized (this.aliasMap) {
      //如果别名缓存中已经存在该数据,则移除
      if (alias.equals(name)) {
        this.aliasMap.remove(alias);
        if (logger.isDebugEnabled()) {
          logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
        }
      }
      else {
        String registeredName = this.aliasMap.get(alias);
        if (registeredName != null) {
          //如果别名已经注册过,直接返回
          if (registeredName.equals(name)) {
            // An existing alias - no need to re-register
            return;
          }
          if (!allowAliasOverriding()) {
            throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                name + "': It is already registered for name '" + registeredName + "'.");
          }
          if (logger.isDebugEnabled()) {
            logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                registeredName + "' with new target name '" + name + "'");
          }
        }
        //检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A
        checkForAliasCircle(name, alias);
        //加入缓存
        this.aliasMap.put(alias, name);
        if (logger.isTraceEnabled()) {
          logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
        }
      }
    }
  }

总结

至此,Spring 加载默认命名空间的 BeanDefinition 的过程就全部分析完了,可以说这是 BeanFactory 实例化前最复杂的逻辑了。我们梳理一下流程:

1、Spring判断是否默认命名空间,加载默认解析器进行解析

2、使用默认命名空间解析完成后得到初步的BeanDefinition对象,再调用自定义命名空间进行处理判断是否需要补充处理。

3、将解析的BeanDefinition 加入beanDefinitionMap缓存中,将beanName加入beanDefinitionNames缓存中,将aliases加入到aliasMap缓存中。

后面我们会继续讲解自定义命名空间的处理过程。



目录
相关文章
|
8天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
7天前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
23天前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
|
23天前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
19天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
46 0
|
24天前
|
XML Java 数据格式
手动开发-简单的Spring基于注解配置的程序--源码解析
手动开发-简单的Spring基于注解配置的程序--源码解析
38 0
|
3月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
5月前
|
XML Java 数据格式
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
46 1
|
2月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
189 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
5月前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
59 0