Spring源码分析(三) XmlBeanDefinitionReader

之前的文章说过,在ioc容器启动时,ApplicationContext的refresh方法里初始化容器,在XmlWebApplicationContext的loadBeanDefinitions方法里调用XmlBeanDefinitionReader读取xml配置文件,那么XmlBeanDefinitionReader是怎么读取配置文件的呢。这篇文章我们就来说一下。先来看一下XmlBeanDefinitionReader的类的结构


XmlBeanDefinitionReader

XmlBeanDefinitionReader实现了BeanDefinitionReader接口,覆写了loadBeanDefinitions方法。

// 获取已经加载过的资源
    Set currentResources = this.resourcesCurrentlyBeingLoaded.get();
    if (currentResources == null) {
        currentResources = new HashSet<>(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }
    if (!currentResources.add(encodedResource)) { // 将当前资源加入记录中。如果已存在,抛出异常
        throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    }
    try {
        // 从 EncodedResource 获取封装的 Resource ,并从 Resource 中获取其中的 InputStream
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) { // 设置编码
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            // 核心逻辑部分,执行加载 BeanDefinition
            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();
        }
    }

在EncodedResource的getReader方法里获取InputStreamReader

public Reader getReader() throws IOException {
    if (this.charset != null) {
        return new InputStreamReader(this.resource.getInputStream(), this.charset);
    }
    else if (this.encoding != null) {
        return new InputStreamReader(this.resource.getInputStream(), this.encoding);
    }
    else {
        return new InputStreamReader(this.resource.getInputStream());
    }
}

然后放到ThreadLocal里

/**
 * 当前线程,正在加载的 EncodedResource 集合。
 */
private final ThreadLocal> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<>("XML bean definition resources currently being loaded");

然后来看下doLoadBeanDefinitions方法

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        throws BeanDefinitionStoreException {
    try {
        // 获取 XML Document 实例
        Document doc = doLoadDocument(inputSource, resource);
        // 根据 Document 实例,注册 Bean 信息
        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);
    }
}

然后就是直接解析xml文件,放到ioc容器中了

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 创建 BeanDefinitionDocumentReader 对象
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    // 获取已注册的 BeanDefinition 数量
    int countBefore = getRegistry().getBeanDefinitionCount();
    // 创建 XmlReaderContext 对象
    // 注册 BeanDefinition
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    // 计算新注册的 BeanDefinition 数量
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

至此,XmlBeanDefinitionReader解析xml文件就完成了。
XmlBeanDefinitionReader的分析就到这里了。

你可能感兴趣的:(Spring源码分析(三) XmlBeanDefinitionReader)