曹工說Spring Boot源碼(6)-- Spring怎麼從xml文件裏解析bean的

寫在前面的話

相關背景及資源:html

曹工說Spring Boot源碼(1)-- Bean Definition究竟是什麼,附spring思惟導圖分享java

曹工說Spring Boot源碼(2)-- Bean Definition究竟是什麼,我們對着接口,逐個方法講解node

曹工說Spring Boot源碼(3)-- 手動註冊Bean Definition不比遊戲好玩嗎,咱們來試一下git

曹工說Spring Boot源碼(4)-- 我是怎麼自定義ApplicationContext,從json文件讀取bean definition的?spring

曹工說Spring Boot源碼(5)-- 怎麼從properties文件讀取beanjson

工程代碼地址 思惟導圖地址設計模式

工程結構圖:數組

總體流程

此次,咱們打算講一下,spring啓動時,是怎麼去讀取xml文件的,bean的解析部分可能暫時涉及不到,由於放到一塊兒,內容就太多了,具體再看吧。dom

  1. ClassPathXmlApplicationContext設置xml文件的路徑ide

  2. refresh內部的beanFactory,其實這時候BeanFactory都還沒建立,會先創DefaultListableBeanFactory

  3. ClassPathXmlApplicationContext調用其loadBeanDefinitions,將新建DefaultListableBeanFactory做爲參數傳入

  4. ClassPathXmlApplicationContext內部會持有一個XmlBeanDefinitionReader,且XmlBeanDefinitionReader內部是持有以前建立的DefaultListableBeanFactory的,這時候就簡單了,XmlBeanDefinitionReader負責讀取xml,將bean definition 解析出來,丟給DefaultListableBeanFactory,此時,XmlBeanDefinitionReader就算完成了,退出歷史舞臺

  5. 上面第四步完成後,DefaultListableBeanFactory裏面其實一個業務bean都沒有,只有一堆的 bean definition,後面ClassPathXmlApplicationContext直接去實例化那些須要在啓動過程當中實例化的bean。

    當前,這中間還涉及到使用beanDefinitionPostProcessorbeanPostProcessor對beanFactory進行處理,這都是後話了。

此次,咱們主要講的部分是,第4步。

入口代碼

位置:org.springframework.context.support.AbstractRefreshableApplicationContext

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            //建立一個DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            // 加載
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

上面調用了

AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
        // 建立一個從xml讀取beanDefinition的讀取器
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // 配置環境
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        // 配置資源loader,通常就是classpathx下去獲取xml
        beanDefinitionReader.setResourceLoader(this);
        // xml解析的解析器
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        // 核心方法,使用beanDefinitionReader去解析xml,並將解析後的bean definition放到beanFactory
        loadBeanDefinitions(beanDefinitionReader);
    }

xml中xsd、dtd解析器

// xml解析的解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

這個類實現的接口就是jdk裏面的org.xml.sax.EntityResolver,這個接口,只有一個方法,主要負責xml裏,外部實體的解析:

public interface EntityResolver {
    
    public abstract InputSource resolveEntity (String publicId,
                                               String systemId)
        throws SAXException, IOException;

}

你們可能不太明白,咱們看看怎麼實現的吧:

public class DelegatingEntityResolver implements EntityResolver {

    /** Suffix for DTD files */
    public static final String DTD_SUFFIX = ".dtd";

    /** Suffix for schema definition files */
    public static final String XSD_SUFFIX = ".xsd";


    private final EntityResolver dtdResolver;

    private final EntityResolver schemaResolver;

    public DelegatingEntityResolver(ClassLoader classLoader) {
        this.dtdResolver = new BeansDtdResolver();
        this.schemaResolver = new PluggableSchemaResolver(classLoader);
    }

    // 主要看這裏,感受就是對咱們xml裏面的那堆xsd進行解析
    @override  
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if (systemId != null) {
            if (systemId.endsWith(DTD_SUFFIX)) {
                return this.dtdResolver.resolveEntity(publicId, systemId);
            }
            else if (systemId.endsWith(XSD_SUFFIX)) {
                return this.schemaResolver.resolveEntity(publicId, systemId);
            }
        }
        return null;
    }

舉個例子,咱們xml裏通常不是有以下代碼嗎:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

上面的代碼,應該就是去獲取和解析上面這裏的xsd,方便進行語法校驗的。畢竟,這個xml咱們也不能隨便亂寫吧,好比,根元素就是 ,有且 只能有一個,下面纔能有0到多個 之類的元素。你要是寫了多個 根元素,確定不合規範啊。

接下來,咱們仍是趕忙切入正題吧,看看XmlBeanDefinitionReader是怎麼解析xml的。

XmlBeanDefinitionReader 解析xml

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        //這個方法還在:AbstractXmlApplicationContext,獲取資源位置,傳給 XmlBeanDefinitionReader
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

通過幾個簡單跳轉,進入下面的方法:

org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String, java.util.Set<org.springframework.core.io.Resource>)
    
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();

        if (resourceLoader instanceof ResourcePatternResolver) {
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                  // 從資源數組裏load bean definition
                int loadCount = loadBeanDefinitions(resources);
                return loadCount;
            }
        }
        
    }

XmlBeanDefinitionReader類圖

這裏插一句,看看其類圖:

總的來講,相似於模板設計模式,一些通用的邏輯和流程,放在AbstractBeanDefinitionReader,具體的解析啊,都是放在子類實現。

咱們這裏也能夠看到,其實現了一個接口,BeanDefinitionReader

package org.springframework.beans.factory.support;

public interface BeanDefinitionReader {
    // 爲何須要這個,由於讀取到bean definition後,須要存到這個裏面去;若是不提供這個,我讀了往哪放
    BeanDefinitionRegistry getRegistry();
    //資源加載器,加載xml之類,固然,做爲一個接口,資源是能夠來自於任何地方
    ResourceLoader getResourceLoader();
    //獲取classloader
    ClassLoader getBeanClassLoader();
    // beanName生成器
    BeanNameGenerator getBeanNameGenerator();
    // 從資源load bean definition
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
    
    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

咱們切回前面,AbstractBeanDefinitionReader實現了大部分方法,除了下面這個:

int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

由於,它畢竟只是個抽象類,不負責幹活啊;並且,爲了可以從不一樣的resource讀取,這個也理應交給子類。

好比,咱們這裏的XmlBeanDefinitionReader就是負責從xml文件讀取;我以前的文章裏,也演示瞭如何從json讀取,也是自定義了一個AbstractBeanDefinitionReader的子類。

讀取xml文件爲InputSource

接着上面的方法往下走,立刻就進入到了:

位置:org.springframework.beans.factory.xml.XmlBeanDefinitionReader,插入的參數,就是咱們的xml
public int loadBeanDefinitions(EncodedResource encodedResource)  {
        ...
        try {
            // 讀取xml文件爲文件流
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                //讀取爲xml資源
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                // 解析bean definition去
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
        }
    }

這裏,提一句InputSource,這個類的全路徑爲:org.xml.sax.InputSource,是jdk裏的類。

包名裏包括了xml,知道大概是xml相關的類了,包名也包含了sax,大概知道是基於sax事件解析模型。

這方面我懂得也很少,回頭能夠單獨講解。咱們繼續正文:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
        try {
            int validationMode = getValidationModeForResource(resource);
             // 反正org.w3c.dom.Document也是jdk的類,具體無論
            Document doc = this.documentLoader.loadDocument(
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
             // 下邊就開始正題了 
            return registerBeanDefinitions(doc, resource);
        }
    }

關於documentLoader.loadDocument,你們只要簡單知道,是進行初步的解析就好了,主要是基於xsd、dtd等,進行語法檢查等。

我這裏的堆棧,你們看下:

這裏,先不深究xml解析的東西(主要是我也不怎麼會啊,哈哈哈)

接着走:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        documentReader.setEnvironment(this.getEnvironment());
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

BeanDefinitionDocumentReader

看得出來,XmlBeanDefinitionReader可能以爲工做繁重,因而將具體的工做,交給了BeanDefinitionDocumentReader

public interface BeanDefinitionDocumentReader {

    void setEnvironment(Environment environment);


    void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
            throws BeanDefinitionStoreException;

}

核心方法確定是

void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

兩個參數,Document咱們理解,就是表明xml文件;

XmlReaderContext

XmlReaderContext是啥,看樣子是個上下文,上下文,通常來講,就是個大雜燴,把須要用到的都會放在裏面。

咱們看看放了些啥:

public class XmlReaderContext extends ReaderContext {
    // 以前的核心類,把本身傳進來了
    private final XmlBeanDefinitionReader reader;
    // org.springframework.beans.factory.xml.NamespaceHandlerResolver,這個也是核心類!
    private final NamespaceHandlerResolver namespaceHandlerResolver;
}

public class ReaderContext {
    //xml資源自己
    private final Resource resource;
    //盲猜是中間處理報錯後,報告問題
    private final ProblemReporter problemReporter;
    // event/listener機制吧,方便擴展
    private final ReaderEventListener eventListener;`
    // 跳過
    private final SourceExtractor sourceExtractor;
}

看完了這個上下文的定義,要知道,它是做爲一個參數,傳給:

org.springframework.beans.factory.xml.BeanDefinitionDocumentReader
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
            throws BeanDefinitionStoreException;

那,這個參數怎麼構造的呢?

那,咱們還得切回前面的代碼:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        documentReader.setEnvironment(this.getEnvironment());
        int countBefore = getRegistry().getBeanDefinitionCount();
        // 這裏,調用createReaderContext(resource)建立上下文
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
/**
     * Create the {@link XmlReaderContext} to pass over to the document reader.
     */
    protected XmlReaderContext createReaderContext(Resource resource) {
        if (this.namespaceHandlerResolver == null) {
             // 建立一個namespacehandler
            this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
        }
        return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
                this.sourceExtractor, this, this.namespaceHandlerResolver);
    }

namespaceHandlerResolver

這裏太核心了,咱們看看namespaceHandlerResolver是幹嗎的:

public interface NamespaceHandlerResolver {

    /**
     * Resolve the namespace URI and return the located {@link NamespaceHandler}
     * implementation.
     * @param namespaceUri the relevant namespace URI
     * @return the located {@link NamespaceHandler} (may be {@code null})
     */
    // 好比解析xml時,咱們可能有<bean>,這個是默認命名空間,其namespace就是<beans>;若是是<context:component-scan>,這裏的namespace,就是context
    NamespaceHandler resolve(String namespaceUri);

}

這個類的用途,就是根據傳入的namespace,找到對應的handler。

你們能夠去spring-beans.jar包裏的META-INF/spring.handlers找一找,這個文件打開後,內容以下:

http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler

也能夠再去spring-context.jar裏找找,裏面也有這個文件:

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

我列了個表格:

namespace handler
http://www.springframework.org/schema/c org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http://www.springframework.org/schema/p org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http://www.springframework.org/schema/util org.springframework.beans.factory.xml.UtilNamespaceHandler
http://www.springframework.org/schema/context org.springframework.context.config.ContextNamespaceHandler
http://www.springframework.org/schema/task org.springframework.scheduling.config.TaskNamespaceHandler
http://www.springframework.org/schema/cache org.springframework.cache.config.CacheNamespaceHandler

比較重要的,我都列在上面了,剩下的jee/lang,我沒用過,不知道你們用過沒,先跳過吧。

你們可能也有感到奇怪的地方,怎麼沒有 這個namespace的呢,由於它是默認的,因此在程序裏是特殊處理的,一會纔到它。

接着看核心邏輯:

DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createHelper(this.readerContext, root, parent);

        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);

        this.delegate = parent;
    }

BeanDefinitionParserDelegate

恩。。。咱們已經快瘋了,怎麼又出來一個類,DefaultBeanDefinitionDocumentReader看來也是以爲本身工做壓力太大了吧,這裏又弄了個BeanDefinitionParserDelegate

這個類,沒實現什麼接口,就是個大雜燴,方法多的一批,主要是進行具體的解析工做,你們能夠看看裏面定義的字段:

public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

    public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";

    /**
     * Value of a T/F attribute that represents true.
     * Anything else represents false. Case seNsItive.
     */
    public static final String TRUE_VALUE = "true";

    public static final String FALSE_VALUE = "false";

    public static final String DEFAULT_VALUE = "default";

    public static final String DESCRIPTION_ELEMENT = "description";

    public static final String AUTOWIRE_NO_VALUE = "no";

    public static final String AUTOWIRE_BY_NAME_VALUE = "byName";

    public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";

    public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";

    public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";

    public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all";

    public static final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple";

    public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects";

    public static final String NAME_ATTRIBUTE = "name";

    public static final String BEAN_ELEMENT = "bean";

    public static final String META_ELEMENT = "meta";

    public static final String ID_ATTRIBUTE = "id";

    public static final String PARENT_ATTRIBUTE = "parent";

    public static final String CLASS_ATTRIBUTE = "class";

    public static final String ABSTRACT_ATTRIBUTE = "abstract";

    public static final String SCOPE_ATTRIBUTE = "scope";

    public static final String SINGLETON_ATTRIBUTE = "singleton";

    public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";

    public static final String AUTOWIRE_ATTRIBUTE = "autowire";

    public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";

    public static final String PRIMARY_ATTRIBUTE = "primary";

    public static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check";

    public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";

    public static final String INIT_METHOD_ATTRIBUTE = "init-method";

    public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";

    public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";

    public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";

    public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";

    public static final String INDEX_ATTRIBUTE = "index";

    public static final String TYPE_ATTRIBUTE = "type";

    public static final String VALUE_TYPE_ATTRIBUTE = "value-type";

    public static final String KEY_TYPE_ATTRIBUTE = "key-type";

    public static final String PROPERTY_ELEMENT = "property";

    public static final String REF_ATTRIBUTE = "ref";

    public static final String VALUE_ATTRIBUTE = "value";

    public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";

    public static final String REPLACED_METHOD_ELEMENT = "replaced-method";

    public static final String REPLACER_ATTRIBUTE = "replacer";

    public static final String ARG_TYPE_ELEMENT = "arg-type";

    public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match";

    public static final String REF_ELEMENT = "ref";

    public static final String IDREF_ELEMENT = "idref";

    public static final String BEAN_REF_ATTRIBUTE = "bean";

    public static final String LOCAL_REF_ATTRIBUTE = "local";
        
        ...

看出來了麼,主要都是xml裏面的那些元素的名稱。

裏面的方法,不少,咱們用到了再說。

咱們繼續回到主線任務:

org.springframework.beans.factory.xml.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>,這個是默認namespace的
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            // 遍歷xml <beans>下的每一個元素
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    // 判斷元素是否是默認命名空間的,好比<bean>是,<context:component-scan>不是
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        //<context:component-scan>,<aop:xxxx>走這邊
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

這裏,判斷一個元素是否是默認命名空間,具體怎麼作的呢:

BeanDefinitionParserDelegate#isDefaultNamespace(org.w3c.dom.Node)   
public boolean isDefaultNamespace(Node node) {
    //調用重載方法
    return isDefaultNamespace(getNamespaceURI(node));
}

public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

public boolean isDefaultNamespace(String namespaceUri) {
        return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
    }

默認namespace時的邏輯

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

第一次發現,原來默認命名空間下,才這麼幾個元素:

import、alias、bean、(NESTED_BEANS_ELEMENT)beans

具體的解析放到下講,這講內容已經夠多了。

非默認namespace時的邏輯

主要是處理:aop、context等非默認namespace

BeanDefinitionParserDelegate
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = getNamespaceURI(ele);
         // 這裏,就和前面串起來了,根據namespace找handler 
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }

咱們挑一個你們最熟悉的org.springframework.context.config.ContextNamespaceHandler,你們先看看:

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

    public void init() {
        // 這個也熟悉吧
        registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
        registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
        // 這個熟悉吧
        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
        registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
    }

}

總之,到了這裏,就是根據具體的元素,找對應的處理器了。這些都後面再說了。內容太多了。

總結

你們能夠回頭再去看看第二章的總體流程,會不會清晰一些了呢?

主要是幾個核心類:

XmlBeanDefinitionReader

BeanDefinitionDocumentReader

XmlReaderContext

namespaceHandlerResolver

BeanDefinitionParserDelegate

內容有點多,你們不要慌,咱們後面還會進一步講解的。以爲有幫助的話,點個贊哦。

相關文章
相關標籤/搜索