Spring源码分析-Bean解析加载为BeanDefiniton(xml方式)

112 阅读4分钟

xml方式

xml配置bean方式解析

分析入口

这里就使用源码提供的测试类,进行调试 image.png

XmlBeanDefinitionReader

用于 XML Bean 定义的 Bean 定义读取器。将实际的 XML 文档读取委托给BeanDefinitionDocumentReader 接口的实现。

@Test
void refToSeparatePrototypeInstances() {
    DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
    reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
    reader.loadBeanDefinitions(REFTYPES_CONTEXT);

    TestBean emma = (TestBean) xbf.getBean("emma");
    TestBean georgia = (TestBean) xbf.getBean("georgia");
    ITestBean emmasJenks = emma.getSpouse();
    ITestBean georgiasJenks = georgia.getSpouse();
    assertThat(emmasJenks).as("Emma and georgia think they have a different boyfriend").isNotSameAs(georgiasJenks);
    assertThat(emmasJenks.getName()).as("Emmas jenks has right name").isEqualTo("Andrew");
    assertThat(emmasJenks).as("Emmas doesn't equal new ref").isNotSameAs(xbf.getBean("jenks"));
    assertThat(georgiasJenks.getName()).as("Georgias jenks has right name").isEqualTo("Andrew");
    assertThat(emmasJenks.equals(georgiasJenks)).as("They are object equal").isTrue();
    assertThat(emmasJenks.equals(xbf.getBean("jenks"))).as("They object equal direct ref").isTrue();
}

上面源码测试类第四行进入

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;

    // Determine ResourceLoader to use.
    if (this.registry instanceof ResourceLoader _resourceLoader) {
       this.resourceLoader = _resourceLoader;
    }
    else {
       this.resourceLoader = new PathMatchingResourcePatternResolver();
    }

    // Inherit Environment if possible
    if (this.registry instanceof EnvironmentCapable environmentCapable) {
       this.environment = environmentCapable.getEnvironment();
    }
    else {
       this.environment = new StandardEnvironment();
    }
}
  • 第10行,创建PathMatchingResourcePatternResolver对象,能够将指定的资源位置路径解析为一个或多个匹配的资源,将资源路径解析成Resource对象。对于xml配置bean方式,就是将xml资源路径解析成Resource对象。
  • 第15行,创建StandardEnvironment对象

构造方法走完,XmlBeanDefinitionReader完成创建。

xml解析

来到refToSeparatePrototypeInstances()测试方法第6行,reader.loadBeanDefinitions(REFTYPES_CONTEXT)

来到下面的代码块

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (logger.isTraceEnabled()) {
       logger.trace("Loading XML bean definitions from " + encodedResource);
    }

    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

    if (!currentResources.add(encodedResource)) {
       throw new BeanDefinitionStoreException(
             "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    }

    try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
       InputSource inputSource = new InputSource(inputStream);
       if (encodedResource.getEncoding() != null) {
          inputSource.setEncoding(encodedResource.getEncoding());
       }
       return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    }
    catch (IOException ex) {
       throw new BeanDefinitionStoreException(
             "IOException parsing XML document from " + encodedResource.getResource(), ex);
    }
    finally {
       currentResources.remove(encodedResource);
       if (currentResources.isEmpty()) {
          this.resourcesCurrentlyBeingLoaded.remove();
       }
    }
}
  • 14行,拿到输入流,这里是xml配置文件资源的输入流。
  • 15行,包装成InputSource。这个类是org.xml.sax包下的,是一个XML 实体的单个输入来源。有了这个就可以进行SAX解析了。
  • 19行,doLoadBeanDefinitions(inputSource, encodedResource.getResource())

doLoadBeanDefinitions

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
       throws BeanDefinitionStoreException {

    try {
       Document doc = doLoadDocument(inputSource, resource);
       int count = registerBeanDefinitions(doc, resource);
       if (logger.isDebugEnabled()) {
          logger.debug("Loaded " + count + " bean definitions from " + resource);
       }
       return count;
    }
    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);
    }
}

第6行进入 中间的一系列校验,创建一些准备对象这里就跳过了,直接来到parseBeanDefinitions 方法

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 ele) {
             if (delegate.isDefaultNamespace(ele)) {
                parseDefaultElement(ele, delegate);
             }
             else {
                delegate.parseCustomElement(ele);
             }
          }
       }
    }
    else {
       delegate.parseCustomElement(root);
    }
}
  • 第8行,来到真正的解析步骤。第11,17行,自定义标签解析。

parseDefaultElement

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);
    }
}

重点看下第9行,Bean标签的解析

processBeanDefinition
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));
    }
}

继续往下走,来到parseBeanDefinitionElement方法解析Bean标签

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    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;
    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");
       }
    }

    if (containingBean == null) {
       checkNameUniqueness(beanName, aliases, ele);
    }

    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);
                // 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);
       return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}

解析完包装成BeanDefinitionHolder对象

registerBeanDefinition

public static void registerBeanDefinition(
       BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
       throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
       for (String alias : aliases) {
          registry.registerAlias(beanName, alias);
       }
    }
}

第7行,注册BeanDefiniton

#### registerBeanDefinition
@Override
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");

    if (beanDefinition instanceof AbstractBeanDefinition abd) {
       try {
          abd.validate();
       }
       catch (BeanDefinitionValidationException ex) {
          throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                "Validation of bean definition failed", ex);
       }
    }

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
       if (!isBeanDefinitionOverridable(beanName)) {
          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 {
       if (isAlias(beanName)) {
          String aliasedName = canonicalName(beanName);
          if (!isBeanDefinitionOverridable(aliasedName)) {
             if (containsBeanDefinition(aliasedName)) {  // alias for existing bean definition
                throw new BeanDefinitionOverrideException(
                      beanName, beanDefinition, getBeanDefinition(aliasedName));
             }
             else {  // alias pointing to non-existing bean definition
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                      "Cannot register bean definition for bean '" + beanName +
                      "' since there is already an alias for bean '" + aliasedName + "' bound.");
             }
          }
          else {
             removeAlias(beanName);
          }
       }
       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;
             removeManualSingletonName(beanName);
          }
       }
       else {
          // Still in startup registration phase
          this.beanDefinitionMap.put(beanName, beanDefinition);
          this.beanDefinitionNames.add(beanName);
          removeManualSingletonName(beanName);
       }
       this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
       resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {
       clearByTypeCache();
    }
}
  • 79行,放入DefaultListableBeanFactory 的private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256)中

  • 80行,放入DefaultListableBeanFactory的private volatile List beanDefinitionNames = new ArrayList<>(256)中

    到此,从xml配置解析完,到注册BeanDefinitioan到DefaultListableBeanFactory工厂中的集合对象中完成。