成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

SpringMVC之源碼分析--HandlerMapping(二)

Imfan / 1701人閱讀

摘要:由于抽象類重寫了父類的方法,所以此時(shí)會(huì)調(diào)用的方法,在該方法中通過調(diào)用父類的方法,該方法通過模板方法模式最終調(diào)到類的方法。分析該類間接實(shí)現(xiàn)了接口,直接實(shí)現(xiàn)該接口的是抽象類,映射與請(qǐng)求。

概述

在前一章https://segmentfault.com/a/1190000014901736的基礎(chǔ)上繼續(xù)分析,主要完成SimpleUrlHandlerMapping類的原理。

本系列文章是基于Spring5.0.5RELEASE。

類圖

在分析類之前,先了解下類的繼承關(guān)系,如下圖:

紅框的類就是我們本章要分析的類。

創(chuàng)建/初始化

從類圖關(guān)系上可以看出,SimpleUrlHanderMapping類最終實(shí)現(xiàn)了ApplicationContextAware接口,該接口定義了方法setApplicationContext(applicationContext),其作用是實(shí)現(xiàn)該接口的類,在Spring實(shí)例化類時(shí),自動(dòng)調(diào)用setApplicationContext(applicationContext)方法。

ApplicationObjectSupport抽象類實(shí)現(xiàn)了ApplicationContextAware接口的setApplicationContext(applicationContext)方法。

由于WebApplicationObjectSupport抽象類重寫了父類ApplicationObjectSupport的initApplicationContext(context)方法,所以此時(shí)會(huì)調(diào)用WebApplicationObjectSupport的initAppliationContext(context)方法,在該方法中通過suppr調(diào)用父類的initApplicationContext(context)方法,該方法通過模板方法模式最終調(diào)到SimpleUrlHandlerMapping類的initApplicationContext()方法。

整個(gè)創(chuàng)建涉及的類比較多,過程比較復(fù)雜,文字描述也很乏味,所以我畫了調(diào)用時(shí)序圖,可供大家參考:

分析到此,我們就找到了SimpleUrlHandlerMapping類的入口方法,即本類的initApplicationContext()方法。

分析

SimpleUrlHandlerMapping

該類間接實(shí)現(xiàn)了org.springframework.web.servlet.HandlerMapping接口,直接實(shí)現(xiàn)該接口的是org.springframework.web.servlet.handler.AbstractHandlerMapping抽象類,映射Url與請(qǐng)求handler bean。支持映射bean實(shí)例和映射bean名稱。源代碼如下:

public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
    // 存儲(chǔ)url和bean映射
    private final Map urlMap = new LinkedHashMap<>();
    // 注入property的name為mappings映射
    public void setMappings(Properties mappings) {
        CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
    }
    // 注入property的name為urlMap映射
    public void setUrlMap(Map urlMap) {
        this.urlMap.putAll(urlMap);
    }
    public Map getUrlMap() {
        return this.urlMap;
    }
    // 實(shí)例化本類實(shí)例入口
    @Override
    public void initApplicationContext() throws BeansException {
        // 調(diào)用父類AbstractHandlerMapping的initApplicationContext方法,只要完成攔截器的注冊(cè)
        super.initApplicationContext();
        // 處理url和bean name,具體注冊(cè)調(diào)用父類完成
        registerHandlers(this.urlMap);
    }
    // 注冊(cè)映射關(guān)系,及將property中的值解析到map對(duì)象中,key為url,value為bean id或name
    protected void registerHandlers(Map urlMap) throws BeansException {
        if (urlMap.isEmpty()) {
            logger.warn("Neither "urlMap" nor "mappings" set on SimpleUrlHandlerMapping");
        }
        else {
            urlMap.forEach((url, handler) -> {
                // 增加以"/"開頭
                if (!url.startsWith("/")) {
                    url = "/" + url;
                }
                // 去除handler bean名稱的空格
                if (handler instanceof String) {
                    handler = ((String) handler).trim();
                }
                // 調(diào)用父類AbstractUrlHandlerMapping完成映射
                registerHandler(url, handler);
            });
        }
    }

}

從以上代碼可知,SimpleUrlHandlerMapping類主要接收用戶設(shè)定的url與handler的映射關(guān)系,其實(shí)際的工作都是交由其父類來完成的。

AbstractHandlerMapping

在創(chuàng)建初始化SimpleUrlHandlerMapping類時(shí),調(diào)用其父類的initApplicationContext()方法,該方法完成攔截器的初始化,代碼如下:

@Override
protected void initApplicationContext() throws BeansException {
    // 空實(shí)現(xiàn)。
    // 子類可重寫此方法以注冊(cè)額外的攔截器
    extendInterceptors(this.interceptors);
    // 從上下文中查詢攔截器并添加到攔截器列表中
    detectMappedInterceptors(this.adaptedInterceptors);
    // 初始化攔截器
    initInterceptors();
}

// 查找實(shí)現(xiàn)了MappedInterceptor接口的bean,并添加到映射攔截器列表
protected void detectMappedInterceptors(List mappedInterceptors) {
    mappedInterceptors.addAll(
            BeanFactoryUtils.beansOfTypeIncludingAncestors(
                    obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

// 將自定義bean設(shè)置到適配攔截器中,bean需實(shí)現(xiàn)HandlerInterceptor或WebRequestInterceptor
protected void initInterceptors() {
    if (!this.interceptors.isEmpty()) {
        for (int i = 0; i < this.interceptors.size(); i++) {
            Object interceptor = this.interceptors.get(i);
            if (interceptor == null) {
                throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
            }
            this.adaptedInterceptors.add(adaptInterceptor(interceptor));
        }
    }
}

AbstractUrlHandlerMapping

在創(chuàng)建初始化SimpleUrlHandlerMapping類時(shí),調(diào)用AbstractUrlHandlerMapping類的registerHandler(urlPath,handler)方法,該方法源碼如下:

protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
    Assert.notNull(urlPath, "URL path must not be null");
    Assert.notNull(handler, "Handler object must not be null");
    Object resolvedHandler = handler;

    // 不是懶加載,默認(rèn)為false,即不是,通過配置SimpleUrlHandlerMapping屬性lazyInitHandlers的值進(jìn)行控制
    // 如果不是懶加載并且handler為單例,即從上下文中查詢實(shí)例處理,此時(shí)resolvedHandler為handler實(shí)例對(duì)象;
    // 如果是懶加載或者h(yuǎn)andler不是單例,即resolvedHandler為handler邏輯名
    if (!this.lazyInitHandlers && handler instanceof String) {
        String handlerName = (String) handler;
        ApplicationContext applicationContext = obtainApplicationContext();
        // 如果handler是單例,通過bean的scope控制
        if (applicationContext.isSingleton(handlerName)) {
            resolvedHandler = applicationContext.getBean(handlerName);
        }
    }

    Object mappedHandler = this.handlerMap.get(urlPath);
    if (mappedHandler != null) {
        if (mappedHandler != resolvedHandler) {
            throw new IllegalStateException(
                    "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
                    "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
        }
    }
    else {
        if (urlPath.equals("/")) {
            if (logger.isInfoEnabled()) {
                logger.info("Root mapping to " + getHandlerDescription(handler));
            }
            setRootHandler(resolvedHandler);
        }
        else if (urlPath.equals("/*")) {
            if (logger.isInfoEnabled()) {
                logger.info("Default mapping to " + getHandlerDescription(handler));
            }
            setDefaultHandler(resolvedHandler);
        }
        else {
            // 把url與handler(名稱或?qū)嵗┓湃雖ap,以供后續(xù)使用
            this.handlerMap.put(urlPath, resolvedHandler);
            if (logger.isInfoEnabled()) {
                logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
            }
        }
    }
}

到此,SimpleUrlHandlerMapping類在容器啟動(dòng)期間的初始化完成。

總結(jié)

本文分析了SimpleUrlHandlerMapping類初始化過程,其實(shí)核心就是把url和handler進(jìn)行了映射,供后續(xù)訪問使用,單靠看文章無法掌握。整個(gè)過程調(diào)用很復(fù)雜,大家多debug跟蹤,一定能了解其內(nèi)部的邏輯。大家共勉!

最后創(chuàng)建了qq群方便大家交流,可掃描加入,同時(shí)也可加我qq:276420284,共同學(xué)習(xí)、共同進(jìn)步,謝謝!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69466.html

相關(guān)文章

  • SpringMVC源碼分析--HandlerMapping(一)

    摘要:接口接口作用是將請(qǐng)求映射到處理程序,以及預(yù)處理和處理后的攔截器列表,映射是基于一些標(biāo)準(zhǔn)的,其中的細(xì)節(jié)因不同的實(shí)現(xiàn)而不相同。該參數(shù)是類型,作用是檢查所有的映射解析器或使用或?yàn)榈模J(rèn)為,即從上下文中檢查所有的。 概述 在Spring MVC啟動(dòng)章節(jié)https://segmentfault.com/a/1190000014674239,介紹到了DispatcherServlet的onRef...

    ralap 評(píng)論0 收藏0
  • SpringMVC源碼分析--HandlerMapping(五)

    摘要:概述通過前三章的分析,我們簡要分析了和,但對(duì)攔截器部分做詳細(xì)的分析,攔截器的加載和初始化是三個(gè)相同的部分。 概述 通過前三章的分析,我們簡要分析了SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,但對(duì)攔截器部分做詳細(xì)的分析,攔截器的加載和初始化是三個(gè)HandlerMapping相...

    nanchen2251 評(píng)論0 收藏0
  • SpringMVC源碼分析--HandlerMapping(三)

    摘要:與類圖對(duì)比,類繼承自抽象類,其又繼承自抽象類,再往上繼承關(guān)系與一致。創(chuàng)建初始化上一章我們分析了的創(chuàng)建初始化過程,的創(chuàng)建初始化過程與一樣,方法的入口在抽象類中的方法。至此,代碼編寫完畢。 概述 本節(jié)我們繼續(xù)分析HandlerMapping另一個(gè)實(shí)現(xiàn)類BeanNameUrlHandlerMapping,從類的名字可知,該類會(huì)根據(jù)請(qǐng)求的url與spring容器中定義的bean的name屬性值...

    fsmStudy 評(píng)論0 收藏0
  • SpringMVC源碼分析--HandlerMapping(六)

    摘要:概述上一節(jié)我們分析了的初始化過程,即創(chuàng)建并注冊(cè),本章我們分析下的請(qǐng)求處理過程,即查找。本系列文章是基于。最后創(chuàng)建了群方便大家交流,可掃描加入,同時(shí)也可加我,共同學(xué)習(xí)共同進(jìn)步,謝謝 概述 上一節(jié)我們分析了RequestMappingHandlerMapping的初始化過程,即創(chuàng)建并注冊(cè)HandlerMehtod,本章我們分析下RequestMappingHandlerMapping的請(qǐng)求...

    BDEEFE 評(píng)論0 收藏0
  • SpringMVC源碼分析--HandlerMapping(四)

    摘要:默認(rèn)支持該策略。以上是對(duì)的宏觀分析,下面我們進(jìn)行內(nèi)部細(xì)節(jié)分析。整體流程一通過實(shí)現(xiàn)接口,完成攔截器相關(guān)組件的初始化調(diào)用類的方法。總結(jié)本文主要分析了的初始化過程,希望對(duì)大家有幫助。隨著學(xué)習(xí)的深入,后面有時(shí)間在分析下期中涉及的關(guān)鍵,比如等等。 概述 本節(jié)我們繼續(xù)分析HandlerMapping另一個(gè)實(shí)現(xiàn)類ReqeustMappingHandlerMapping,該類是我們?nèi)粘i_發(fā)中使用最多的...

    imccl 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<