1. 程式人生 > >spring原始碼(三)--XmlBeanDefinitionReader

spring原始碼(三)--XmlBeanDefinitionReader

類繼承層次圖: 這裡寫圖片描述

類名 作用
BeanDefinitionReader 定義資原始檔讀取並轉換為BeanDefinition的功能
EnvironmentCapable 定義了獲取Environment的方法
AbstractBeanDefinitionReader 對上面2個介面做了實現

XmlBeanDefinitionReader讀取配置檔案的大致流程

  1. 通過繼承自 AbstractBeanDefinitionReader 的方法,使用ResourceLoader將資原始檔路徑轉換為Resource
  2. 使用DocumentLoader對Resource檔案進行轉換,將Resource檔案轉換為Document檔案
  3. 使用BeanDefinitionDocumentReader的實現類DefaultBeanDefinitionDocumentReader對Document進行解析,並使用BeanDefinitionParserDelegate對Element進行解析

核心方法loadBeanDefinitions:

  1. 把編碼源新增到currentResources 中
  2. 把inputStream轉換為inputSource
  3. 使用DefaultDocumentLoader把 inputStream轉換為Doucument
  4. 解析document,把bean註冊到factory
 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if(this.logger.isInfoEnabled()) {
            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if(currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }

        if(!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
                InputStream inputStream = encodedResource.getResource().getInputStream();

                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if(encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }

                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                    inputStream.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if(((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var5;
        }
    }

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
            Document doc = this.doLoadDocument(inputSource, resource);
            return this.registerBeanDefinitions(doc, resource);
    }
    //這裡的EntityResolver一般是ResourceEntityResolver(二般情況是DelegatingEntityResolver)
 protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware());
    }
    

對與xml檔案中的一個個元素節點,由下面的方法遍歷 方法在DefaultBeanDefinitionDocumentReader中

//root是dom節點的根節點,從根節點開始遍歷,對於不同名稱空間的元素使用不同的解析器解析,然後把符合條件的bean註冊到factory中。
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)) {//是預設名稱空間中的節點,由當前reader解析
                        this.parseDefaultElement(ele, delegate);
                    } else {//否則由delegate解析,多種parser在第十篇中有描述
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }

    }

關於EncodedResource,提供了reader物件,沒有設定字符集和編碼時,將使用預設的字符集解碼。

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