<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    張昊

    J-Hi(http://www.j-hi.net)

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      45 Posts :: 1 Stories :: 110 Comments :: 0 Trackbacks

    1          首先該類有一靜態(tài)語塊,用以加載缺省策略。

        static {

                ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);

                defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);

    }

    缺省的策略文件為當(dāng)前包下的DispatcherServlet.properties,主要包括

    LocaleResolver(本地化解析器,AcceptHeaderLocaleResolver)

    ThemeResolver(主題解析器,FixedThemeResolver)

    HandlerMapping(處理器映射,BeanNameUrlHandlerMapping)

    HandlerAdapter(控制適配器,多個(gè))

    ViewResolver(視圖解析器,InternalResourceViewResolver)

    RequestToViewNameTranslator(請(qǐng)求到視圖名的翻譯器,DefaultRequestToViewNameTranslator)

    2          通過繼承關(guān)系調(diào)用HttpServletBean類的init()初始化方法


        在該方法體內(nèi),首先將這個(gè)servlet視為一個(gè)bean對(duì)其包裝并將配置文件中當(dāng)前servlet下的初始參數(shù)值賦倒這個(gè)servlet中。然后調(diào)用子類(FrameworkServlet)initServletBean(),而子類通過模板模式再調(diào)用其子類(DispatcherServlet)的initFrameworkServlet()方法。在initServletBean()方法中主要代碼片段如下:

                this.webApplicationContext = initWebApplicationContext();

                initFrameworkServlet();

    而在initWebApplicationContext(),它首先是從ServletContext中獲得由ContextLoader類設(shè)置進(jìn)的keyWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE屬性的值(即Spring容器的實(shí)例),然后以實(shí)例為parent創(chuàng)建一個(gè)新的容器。這也是為什么說一個(gè)DispatcherServlet就對(duì)應(yīng)一個(gè)WebApplicationContext(每個(gè)DispatcherServlet都有各自的上下文)。最后將該WebApplicationContext綁定到到ServletContext,如果允許發(fā)布話

    由此可以看出:

    WebApplicationContextUtils.getWebApplicationContext(servletContext)

    servletContext.getAttribute(SERVLET_CONTEXT_PREFIX+ getServletName())之間的主要區(qū)別在于:后者包括了該servlet的所有配置信息而前者是全局性的沒有這部分信息

    3          DispatcherServletinitFrameworkServlet()方法初始化工作

            initMultipartResolver();

            initLocaleResolver();

            initThemeResolver();

            initHandlerMappings();

            initHandlerAdapters();

            initHandlerExceptionResolvers();

            initRequestToViewNameTranslator();

            initViewResolvers();

        如果在配置文件沒有設(shè)置將缺省的策略文件DispatcherServlet.properties。由此可見,因?yàn)?/span>DispatcherServlet是單例的,所以設(shè)置的信息是全局的也就是所有的解析器不能動(dòng)態(tài)的變化。

    4          當(dāng)調(diào)用類FrameworkServlet中的doGet()/doPost()/doPut()/doDelete()方法時(shí)

    以上方法均調(diào)用相同方法processRequest(request, response)。注意:Spring放棄了對(duì)HttpServletservice()方法的覆蓋而用具體的操作方法取代。

    5          調(diào)用類FrameworkServlet中的processRequest(request, response)方法

            try {

            doService(request, response);

         }

            finally {

                if (isPublishEvents()) {

                    this.webApplicationContext.publishEvent(

                        new ServletRequestHandledEvent(this,

                        request.getRequestURI(), request.getRemoteAddr(),

                        request.getMethod(), getServletConfig().getServletName(),

                        WebUtils.getSessionId(request), getUsernameForRequest(request),

                                    processingTime, failureCause));

                }

         }

    通過代碼摘要可以看出該類有一個(gè)webApplicationContext引用,除了執(zhí)行doService()這個(gè)核心方法外,每次都會(huì)發(fā)布一個(gè)ServletRequestHandledEvent事件如果publishEventstrue,其值可以在web.xml文件中增加添加context參數(shù),或servlet初始化參數(shù)(

    <init-param>

    <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/application.xml</param-value>

    </init-param>)

    DispatcherServlet初始化參數(shù)

    參數(shù)

    描述

    contextClass

    實(shí)現(xiàn)WebApplicationContext接口的類,當(dāng)前的servlet用它來創(chuàng)建上下文。如果這個(gè)參數(shù)沒有指定,默認(rèn)使用XmlWebApplicationContext

    contextConfigLocation

    傳給上下文實(shí)例(由contextClass指定)的字符串,用來指定上下文的位置。這個(gè)字符串可以被分成多個(gè)字符串(使用逗號(hào)作為分隔符)來支持多個(gè)上下文(在多上下文的情況下,如果同一個(gè)bean被定義兩次,后面一個(gè)優(yōu)先)。

    namespace

    WebApplicationContext命名空間。默認(rèn)值是[server-name]-servlet

    publishContext

    我們發(fā)布的context是作為ServletContext的一個(gè)屬性嗎?默認(rèn)值為true,屬性名為SERVLET_CONTEXT_PREFIX+ getServletName()

    publishEvents

    在執(zhí)行每個(gè)請(qǐng)求后是否發(fā)布一個(gè)ServletRequestHandledEvent事件?默認(rèn)值為true

        以上參數(shù)的初始加載是在HttpServletBean類的init()中,而所有DispatcherServlet的解析器是在initFrameworkServlet()方法中。

    由此可見,DispatcherServlet的初始參數(shù)加載來源可分為兩部分,

    5.1       web.xml文件對(duì)于該servlet配置的<init-param>初始參數(shù)中

    5.2       通過SpringIOC容器實(shí)例化后,通過該類的初始化方法,將容器內(nèi)的實(shí)例一一引用

    6          調(diào)用類DispatcherServlet中的doService(request, response)方法

    暴露在request屬性中DispatchServlet的一些特性,并且調(diào)用doDispatch(request, response)方法執(zhí)行真正的分發(fā)動(dòng)作。

             request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());

    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);

        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);

        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

        try {

            doDispatch(request, response);

        }

    7          調(diào)用類DispatcherServlet中的doDispatch(request, response)方法

    7.1         在區(qū)域上下文持有者(LocaleContextHolder中當(dāng)前線程下的值做一次替換。暴露當(dāng)前localeResolverrequest中的Locale

            LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();

            LocaleContextHolder.setLocaleContext(new LocaleContext() {

                public Locale getLocale() {

                    returnlocaleResolver.resolveLocale(request);

                }});

    由源碼可見,將當(dāng)前線程下的LocaleContext取出,再?gòu)漠?dāng)前區(qū)域解析器(LocaleResolver)中得到Locale前創(chuàng)建為LocaleContext后再賦到LocaleContextHolder

    7.2       在請(qǐng)求上下文持有者(RequestContextHolder中當(dāng)前線程下的值做一次替換。暴露當(dāng)前RequestAttributes到當(dāng)前線程中

    RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();

    ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);

    RequestContextHolder.setRequestAttributes(requestAttributes);

        在此注意,ServletRequestAttributes類只能獲得sessionrequest有屬性,而無法獲得request的參數(shù)(parameter)

    7.3       轉(zhuǎn)換requestMultipartHttpServletRequest類型的實(shí)例,如果不是就簡(jiǎn)單的返回

            protected HttpServletRequest checkMultipart(HttpServletRequest request) {

    if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {

                if (request instanceof MultipartHttpServletRequest) {

                }

                else

                    returnthis.multipartResolver.resolveMultipart(request);

                }

            return request;

        }

    由代碼可以看出,如果要支持文件上傳要有兩個(gè)前提

        1.在應(yīng)用的配置文件中添加MultipartResolver(分段文件解析器),目前Spring支持兩種上傳文件的開源項(xiàng)目Commons FileUpload(http://jakarta.apache.org/commons/fileupload)COSFileUpload (http://www.servlets.com/cos)

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
    <bean id="multipartResolver" class="org.springframework.web.multipart.cos.CosMultipartResolver"/>

    注意:Beanid必須為multipartResolver’, DispatcherServlet中的成員屬性this.multipartResolver是在初始化時(shí)與容器中的實(shí)例引用在一起的。

        2. 通過multipartResolver.isMultipart(request)判斷requestContextType是否是multipart/form-data。所以表單格式應(yīng)為

            <form method="post" action="upload.form" enctype="multipart/form-data">
                <input type="file" name="file"/><input type="submit"/>
            這個(gè)元素的名字(“file”)和服務(wù)器端處理這個(gè)表單的bean(在下面將會(huì)提到)中類型為byte[]的屬性名相同。在這個(gè)表單里我們也聲明了編碼參數(shù)(enctype="multipart/form-data")以便讓瀏覽器知道如何對(duì)這個(gè)文件上傳表單進(jìn)行編碼

    最后由相應(yīng)的MultipartResolver(分段文件解析器)request封裝為與解析器對(duì)應(yīng)的MultipartHttpServletRequest實(shí)例并返回

          

    7.4       根據(jù)當(dāng)前請(qǐng)求URL為其找到指定的處理器(handler)與欄截器(HandlerInterceptor),并將它們封裝為HandlerExecutionChain實(shí)例。

    HandlerExecutionChain mappedHandler = getHandler(processedRequest, false);

    在此過程中分為如下幾個(gè)步驟

    1.    循環(huán)所有已注冊(cè)的HandlerMapping(處理器映射),對(duì)于不同的處理器映射對(duì)其映射的處理方式不同。BeanNameUrlHandlerMapping只要在配置文件中bean元素的name屬性以/開頭它都認(rèn)為是一個(gè)映射如<bean name=”/editaccount”>。而SimpleUrlHandlerMapping只關(guān)注自身定義的<property name=”mappings”>下的那些映射,而且支持Ant風(fēng)格的定義

    2.    通過客戶請(qǐng)求的URL與處理器映映射的鍵值做匹配(也可以使用Ant風(fēng)格匹配,參見AbstractUrlHandlerMapping.lookupHandler()方法),如果滿足匹配條件,就返回與其對(duì)應(yīng)的處理器(Handler),一般情況下,都是Controller(控制器)接口子孫類的實(shí)例。

    3.    根據(jù)匹配上的處理器映射取得攔截器數(shù)組,并與找到的處理器一同作為構(gòu)建函數(shù)的參數(shù)創(chuàng)建出HandlerExecutionChain實(shí)例

    7.5       執(zhí)行所有攔截器的前置方法

    HandlerInterceptor接口提供了如下三個(gè)方法:

    1.    preHandle(…)前置方法,在處理器執(zhí)行前調(diào)用,當(dāng)返回false時(shí),DispatcherServlet認(rèn)為該攔截器已經(jīng)處理完了請(qǐng)求,而不再繼續(xù)執(zhí)行執(zhí)行鏈中的其它攔截器和處理器

    2.    postHandle(…)后置方法,在處理器執(zhí)行后調(diào)用

    3.    afterCompletion(…)完成前置方法,在整個(gè)請(qǐng)求完后調(diào)用。注意如果第n個(gè)攔截器的preHandle方法返回的是false則只會(huì)調(diào)用第n個(gè)攔截器之前所有該方法,而n++不會(huì)被調(diào)用

    另:Spring還提供了一個(gè)adapterHandlerInterceptorAdapter讓用戶更方便的擴(kuò)展HandlerInterceptor接口

    7.6       獲得與當(dāng)前處理器相匹配的HandlerAdapter(處理器適配器)

        protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

            Iterator it = this.handlerAdapters.iterator();

            while (it.hasNext()) {

                HandlerAdapter ha = (HandlerAdapter) it.next();

                if (ha.supports(handler)) {

                    return ha;

                }

        }

    循環(huán)所有已注冊(cè)的HandlerAdapter(處理器適配器),如果該適配器支持ha.supports(handler)當(dāng)前處理器,就返回。由此可見,Spring通過HandlerAdapter使處理器解耦,實(shí)處理器(Handler)不只是僅僅局限于控制器(Controller)這一種形式。目前Spring可以支持,ServletHttpRequestHandlerThrowawayControllerController,從這一點(diǎn)上看Spring已為客戶留出了很大空間作為擴(kuò)展的口子。

    7.7       根據(jù)處理器適配器調(diào)用處理器的指定方法,執(zhí)行真正的處理操作。如Controller(控制器)接口調(diào)用handleRequest() ThrowawayController接口調(diào)用execute()Servlet接口調(diào)用service()….但無論調(diào)用那種自理器,HandlerAdapter中的handle()方法都要求返回ModelAndView的一個(gè)實(shí)例

    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    Spring中最常用的處理器是以Controller接口下的所有子孫類控制器,繼承結(jié)構(gòu)如圖


    在這些控制器中又以SimpleFormController控制器最為常用,下圖為該類的完整執(zhí)行過程


     

    7.8       執(zhí)行所有攔截器的后置方法

    7.9       根據(jù)處理器(Handle)返回的ModelAndView對(duì)象,找到或創(chuàng)建View對(duì)象,并調(diào)用View對(duì)象的render()方法

    render(mv, processedRequest, response)

    在此有幾個(gè)關(guān)鍵性的概念:

    ModelAndView:它是模形(Model,實(shí)際上只是一個(gè)Map,最終會(huì)將模形存放到request的屬性中,以Mapkeyrequest屬性的鍵,Mapvalue為值)與視圖(View)的持有者。而View又提供了兩種形態(tài),即以View接口為祖先的實(shí)例對(duì)象,以字符串的視圖的名字。該類通過isReference()方法判斷是一個(gè)字符串的引用還是一個(gè)真正的View對(duì)象。注意:該類有些奇怪:它將有狀態(tài)的Model與無狀態(tài)的View合并到一個(gè)類中,這就導(dǎo)致每次請(qǐng)求都到對(duì)該類型的實(shí)例進(jìn)行創(chuàng)建,而不無緩存。View對(duì)象Spring提供了緩存功能。

    ViewResolver(視圖解析器):主要提供的功能是從視圖名稱到實(shí)際視圖的映射。也就是說只有ModelAndViewisReference()返回true時(shí),才會(huì)對(duì)視圖的名字做解析工作。這使視圖解析與真正的視圖相分離,這樣我們就可以通過不同的方式配置視圖,如可以采用propertiesxml或是提供URI的前、后綴等形式配置視圖。但要注意視圖解析器與視圖之間還是緊密的關(guān)系,Sping在此沒實(shí)現(xiàn)全部的完全解耦

    ViewResolver

    描述

    AbstractCachingViewResolver

    抽象視圖解析器實(shí)現(xiàn)了對(duì)視圖的緩存。在視圖被投入使用之前,通常需要進(jìn)行一些準(zhǔn)備工作。從它繼承的視圖解析器將對(duì)要解析的視圖進(jìn)行緩存。

    InternalResourceViewResolver

    作為UrlBasedViewResolver的子類,它支持InternalResourceView(對(duì)ServletJSP的包裝),以及其子類JstlViewTilesView。通過setViewClass方法,可以指定用于該解析器生成視圖使用的視圖類。

    UrlBasedViewResolver

    UrlBasedViewResolver實(shí)現(xiàn)ViewResolver,將視圖名直接解析成對(duì)應(yīng)的URL,不需要顯式的映射定義。如果你的視圖名和視圖資源的名字是一致的,就可使用該解析器,而無需進(jìn)行映射。

    ResourceBundleViewResolver

    ResourceBundleViewResolver實(shí)現(xiàn)ViewResolver,在一個(gè)ResourceBundle中尋找所需bean的定義。這個(gè)bundle通常定義在一個(gè)位于classpath中的屬性文件中。默認(rèn)的屬性文件是views.properties

    XmlViewResolver

    XmlViewResolver實(shí)現(xiàn)ViewResolver,支持XML格式的配置文件。該配置文件必須采用與Spring XML Bean Factory相同的DTD。默認(rèn)的配置文件是/WEB-INF/views.xml

    VelocityViewResolver / FreeMarkerViewResolver

    作為UrlBasedViewResolver的子類,它能支持VelocityView(對(duì)Velocity模版的包裝)和FreeMarkerView以及它們的子類。

    View(視圖):處理請(qǐng)求的準(zhǔn)備工作,并將該請(qǐng)求提交給某種具體的視圖技術(shù)。

    如,InternalResourceView會(huì)通過RequestDispatcher類調(diào)用include()forward()方法

      RedirectView會(huì)通過HttpServletResponse類調(diào)用sendRedirect()方法

    AbstractExcelView會(huì)產(chǎn)生一個(gè)輸出流

    區(qū)別:

    1forwardinclude區(qū)別在于forward本意是讓第一個(gè)頁(yè)面處理request,第二個(gè)頁(yè)面處理response.調(diào)用第二個(gè)頁(yè)面后,程序還會(huì)返回第一個(gè)頁(yè)面繼續(xù)執(zhí)行,但是此時(shí)再使用response輸出已經(jīng)沒有作用了;include服務(wù)器端的動(dòng)態(tài)加載,執(zhí)行完第二個(gè)頁(yè)面的程序后可以回到第一個(gè)頁(yè)面繼續(xù)輸出,即將第二個(gè)頁(yè)面的輸出拉到第一個(gè)頁(yè)面中。

    2forwardinclude共享Request范圍內(nèi)的對(duì)象,redirect則不行,即:如果一個(gè)javabean被聲明為request范圍的話,則被forward到的資源也可以訪問這個(gè)javabean,redriect則不行。

    3forwardinclude基本上都是轉(zhuǎn)發(fā)到context內(nèi)部的資源,而redirect可以重定向到外部的資源,如: req.sendRedriect("http://www.mocuai.com");


    posted on 2011-03-10 14:23 張昊 閱讀(9148) 評(píng)論(2)  編輯  收藏

    Feedback

    # re: SpringMVC:DispatcherServlet代碼分析及運(yùn)行過程 2011-03-10 15:58 窩窩影視
    分析的不錯(cuò)。。。先留言,然后仔細(xì)的看看  回復(fù)  更多評(píng)論
      

    # re: SpringMVC:DispatcherServlet代碼分析及運(yùn)行過程 2011-03-28 13:34 ocaicai
    有圖有真相,不錯(cuò)!  回復(fù)  更多評(píng)論
      


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲国产视频久久| 中美日韩在线网免费毛片视频| 免费高清A级毛片在线播放| 中文字幕无码毛片免费看| 日韩精品成人无码专区免费 | 天天操夜夜操免费视频| 亚洲午夜成人精品电影在线观看| 91亚洲精品第一综合不卡播放| 亚洲丁香婷婷综合久久| 久久国产精品国产自线拍免费| 啦啦啦手机完整免费高清观看| 亚洲性在线看高清h片| 亚洲成在人线中文字幕| 九九免费观看全部免费视频| 免费黄色网址网站| 狠狠亚洲狠狠欧洲2019| 2020亚洲男人天堂精品| 免费看少妇高潮成人片| 国产无遮挡色视频免费视频| 亚洲伊人久久大香线蕉苏妲己| 免费的黄色网页在线免费观看| 免费看片在线观看| 亚洲成AV人片在WWW色猫咪 | 亚洲人成色77777在线观看| 波多野结衣免费一区视频| 日本无吗免费一二区| 亚洲精品乱码久久久久久下载| 久香草视频在线观看免费| 成人啪精品视频免费网站| 亚洲AV日韩AV天堂久久| 黄色毛片免费观看| 在线视频免费观看高清| 亚洲av无码乱码国产精品fc2| 免费无码国产在线观国内自拍中文字幕| 国产电影午夜成年免费视频| 国产亚洲精品a在线无码| 国产精品成人亚洲| 成人性生交视频免费观看| 亚洲国产精品网站久久| 国产免费无码一区二区| 亚洲视频在线精品|