springmvc解析springmvc-servlet.xml標(biāo)簽的過程

spring解析applicationContext.xml配置文件的document對(duì)象的過程,大體分為默認(rèn)標(biāo)簽的解析和自定義標(biāo)簽的解析
默認(rèn)標(biāo)簽有import標(biāo)簽明郭、alias標(biāo)簽慈俯、bean標(biāo)簽和beans標(biāo)簽豪墅。如下:
//這個(gè)就是bean
public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;

public static final String NESTED_BEANS_ELEMENT = "beans";

public static final String ALIAS_ELEMENT = "alias";

public static final String IMPORT_ELEMENT = "import";

public static final String RESOURCE_ATTRIBUTE = "resource";



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);
    }
}
自定義標(biāo)簽的解析代碼如下
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    if (namespaceUri == null) {
        return null;
    }
    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));
}

過程

  • 獲取元素(Element)的(命名空間uri)namespaceUri第股。每個(gè)命名空間uri,都會(huì)有一個(gè)默認(rèn)的解析器
  • 根據(jù)namespaceUri獲取該元素的處理器(NameSpaceHandler)
  • 使用獲取到的處理器處理該標(biāo)簽

該過程中吼拥,我認(rèn)為比較需要注意的是第二步倚聚,即獲取該標(biāo)簽的處理器的過程。下面做一下詳細(xì)解釋

每次獲取標(biāo)簽的處理器的時(shí)候凿可,都會(huì)調(diào)用如下的方法.

//org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve

public NamespaceHandler resolve(String namespaceUri) {
        Map<String, Object> handlerMappings = getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        }
        else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler) handlerOrClassName;
        }
        else {
            String className = (String) handlerOrClassName;
            try {
                Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                    throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                            "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                }
                NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                namespaceHandler.init();
                handlerMappings.put(namespaceUri, namespaceHandler);
                return namespaceHandler;
            }
            catch (ClassNotFoundException ex) {
                throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
                        "] for namespace [" + namespaceUri + "]", ex);
            }
            catch (LinkageError err) {
                throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
                        className + "] for namespace [" + namespaceUri + "]", err);
            }
        }
    }

看一下該方法的第一行代碼惑折,獲取handlerMapping。

/**
     * Load the specified NamespaceHandler mappings lazily.
     */
    private Map<String, Object> getHandlerMappings() {
        Map<String, Object> handlerMappings = this.handlerMappings;
        if (handlerMappings == null) {
            synchronized (this) {
                handlerMappings = this.handlerMappings;
                if (handlerMappings == null) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
                    }
                    try {
                        Properties mappings =
                        PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                        if (logger.isTraceEnabled()) {
                            logger.trace("Loaded NamespaceHandler mappings: " + mappings);
                        }
                        handlerMappings = new ConcurrentHashMap<>(mappings.size());
                        CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    }
                    catch (IOException ex) {
                        throw new IllegalStateException(
                                "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
                    }
                }
            }
        }
        return handlerMappings;
    }

查看方法
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);

public static Properties loadAllProperties(String resourceName, @Nullable ClassLoader classLoader) throws IOException {
        Assert.notNull(resourceName, "Resource name must not be null");
        ClassLoader classLoaderToUse = classLoader;
        if (classLoaderToUse == null) {
            classLoaderToUse = ClassUtils.getDefaultClassLoader();
        }
        Enumeration<URL> urls = (classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) :
                ClassLoader.getSystemResources(resourceName));
        Properties props = new Properties();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            URLConnection con = url.openConnection();
            ResourceUtils.useCachesIfNecessary(con);
            try (InputStream is = con.getInputStream()) {
                if (resourceName.endsWith(XML_FILE_EXTENSION)) {
                    if (shouldIgnoreXml) {
                        throw new UnsupportedOperationException("XML support disabled");
                    }
                    props.loadFromXML(is);
                }
                else {
                    props.load(is);
                }
            }
        }
        return props;
    }

這里傳入的resouceName的值是

    public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";

所以該方法的最終目的是從classpath下去獲取resources/META-INF/spring.handlers文件中的鍵值對(duì)值枯跑,放入到props中惨驶。

例如spring-mvc模塊中,resources/META-INF/spring.handlers文件中的內(nèi)容是:

http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler

spring-beans模塊中敛助,resources/META-INF/spring.handlers文件的內(nèi)容是:

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-aop模塊中粗卜,resources/META-INF/spring.handlers文件的內(nèi)容是:

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

spring-context模塊中,resources/META-INF/spring.handlers文件的內(nèi)容是:

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

spring-tx模塊中纳击,resources/META-INF/spring.handlers文件的內(nèi)容是:

http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

spring-oxm模塊中续扔,resouces/META-INF/spring.handlers文件的內(nèi)容是:

http\://www.springframework.org/schema/oxm=org.springframework.oxm.config.OxmNamespaceHandler

在我自己的測(cè)試模塊中,走到這一步焕数,handlerMappings里面的值為


image.png

當(dāng)然纱昧,這里的模塊中的值跟你依賴的spring的模塊有關(guān),你也可以在自己的項(xiàng)目中的resources/META-INF/spring.handlers文件中定義自己的標(biāo)簽處理器堡赔。

handlerMappings這個(gè)map中识脆,key為namespaceUri。value為標(biāo)簽處理器善已。
這樣我們就可以通過namespaceUri灼捂,來獲取各自的標(biāo)簽處理器

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市换团,隨后出現(xiàn)的幾起案子悉稠,更是在濱河造成了極大的恐慌,老刑警劉巖啥寇,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件偎球,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡辑甜,警方通過查閱死者的電腦和手機(jī)衰絮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來磷醋,“玉大人猫牡,你說我怎么就攤上這事。” “怎么了勺三?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵吴攒,是天一觀的道長灾炭。 經(jīng)常有香客問我,道長贱案,這世上最難降的妖魔是什么暇榴? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任举户,我火速辦了婚禮器联,結(jié)果婚禮上二汛,老公的妹妹穿的比我還像新娘。我一直安慰自己拨拓,他們只是感情好肴颊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渣磷,像睡著了一般婿着。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上醋界,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天竟宋,我揣著相機(jī)與錄音,去河邊找鬼物独。 笑死袜硫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的挡篓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼帚称,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼官研!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闯睹,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤戏羽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后楼吃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體始花,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年孩锡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了酷宵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡躬窜,死狀恐怖浇垦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荣挨,我是刑警寧澤男韧,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布朴摊,位于F島的核電站,受9級(jí)特大地震影響此虑,放射性物質(zhì)發(fā)生泄漏甚纲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一朦前、第九天 我趴在偏房一處隱蔽的房頂上張望介杆。 院中可真熱鬧,春花似錦况既、人聲如沸这溅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悲靴。三九已至,卻和暖如春莫其,著一層夾襖步出監(jiān)牢的瞬間癞尚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國打工乱陡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浇揩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓憨颠,卻偏偏與公主長得像胳徽,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子爽彤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容