Spring DispatcherServlet與handlerinterceptor 的區別

3.一、DispatcherServlet做用

DispatcherServlet是前端控制器設計模式的實現,提供Spring Web MVC的集中訪問點,並且負責職責的分派,並且與Spring IoC容器無縫集成,從而能夠得到Spring的全部好處。 。html

DispatcherServlet主要用做職責調度工做,自己主要用於控制流程,主要職責以下:前端

一、文件上傳解析,若是請求類型是multipart將經過MultipartResolver進行文件上傳解析;java

二、經過HandlerMapping,將請求映射處處理器(返回一個HandlerExecutionChain,它包括一個處理器、多個HandlerInterceptor攔截器);web

三、經過HandlerAdapter支持多種類型的處理器(HandlerExecutionChain中的處理器);spring

四、經過ViewResolver解析邏輯視圖名到具體視圖實現;設計模式

五、本地化解析;app

六、渲染具體的視圖等;jsp

七、若是執行過程當中遇到異常將交給HandlerExceptionResolver來解析。ide

從以上咱們能夠看出DispatcherServlet主要負責流程的控制(並且在流程中的每一個關鍵點都是很容易擴展的)。ui

3.1.1 DispatherServlet 繼承類關係

假如咱們要實現一個請求home.htm而後返回home.jsp視圖資源則

當home.htm請求到達時,咱們須要DispatcherServlet來處理該請求,因此首先配置該Servlet

第一步須要在web.xml中配置DispatcherServlet,使該servlet來接收請求並作進一步處理。

[html] view plaincopyprint?

  1. <servlet>  
        <servlet-name>dispatch</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>dispatch</servlet-name>  
        <url-pattern>*.htm</url-pattern>  
    </servlet-mapping>


這個部分很好理解,若是請求以.htm結尾則交給名爲dispatch類爲DispatcherServlet的Servlet處理。


從類圖中很容易看出DispatcherServlet最終繼承的是HttpServlet,也就是說它一樣知足Servlet的工做原理

Servlet初始化時須要調用init方法,在HttpServletBean中實現,該init方法調用了initServletBean,該方法在FrameworkServlet中實現

initServletBean主要初始化關於配置文件的內容,好比{servlet-name}-servlet.xml


第二步,須要在/WebRoot/WEB-INF下新建名爲{servlet-name}-servlet.xml的spring bean配置文件。(該示例中即爲dispatch-servlet.xml)

在初始化過程當中會去尋找該配置文件,固然咱們也能夠本身去設置參數來更改配置文件所在路徑


好比咱們若是在src下新建的該配置文件dispatch-servlet,在編譯後會被複制到WEB-INF/classes文件夾下,

配置文件仍是按照命名規範作吧(能夠修改成其餘名字)

  1. <servlet>  
            <servlet-name>dispatch</servlet-name>  
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
            <init-param>  
                <param-name>namespace</param-name>  
                <param-value>classes/dispatch-servlet</param-value>  
            </init-param>  
            <load-on-startup>1</load-on-startup>  
        </servlet>


此時的配置就會去尋找/WEB-INF/classes/dispatch-servlet.xml


當請求到達後Servlet將調用service方法進行處理,因爲咱們是經過輸入網址方式的get方法請求,Servlet將調用doGet方法

此處的doGet方法在FrameworkServlet中實現,doGet方法調用processRequest方法,processRequest則調用doService方法處理

而doService在DispatcherServlet中實現,doService再調用了DispatcherServlet的doDispatch方法,

該方法則會根據request找到轉發對象,並進行請求轉發操做,

下面是獲取實際的視圖資源部分

  1. public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
                throws Exception {  
      
            return ((Controller) handler).handleRequest(request, response);  
        }


這裏須要咱們本身實現Controller接口並實現handleRequest方法,返回對應的ModelAndView對象。


下面是請求轉發的部分

  1. /** 
         * Render the internal resource given the specified model. 
         * This includes setting the model as request attributes. 
         */  
        @Override  
        protected void renderMergedOutputModel(  
                Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {  
      
            // Determine which request handle to expose to the RequestDispatcher.  
            HttpServletRequest requestToExpose = getRequestToExpose(request);  
      
            ...  
                     exposeModelAsRequestAttributes(model, requestToExpose);//這個方法看下面源碼,request.setAttribute操做  
                      // Determine the path for the request dispatcher.  
            String dispatcherPath = prepareForRendering(requestToExpose, response);  
      
                ...  
      
            // If already included or response already committed, perform include, else forward.  
            if (useInclude(requestToExpose, response)) {  
                ......  
            }  
      
            else {//重點看這部分,在根據請求以及配置文件獲取到RequestDispatcher 對象以後,使用該對象作轉發處理  
                // Note: The forwarded resource is supposed to determine the content type itself.  
                exposeForwardRequestAttributes(requestToExpose);  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");  
                }  
                rd.forward(requestToExpose, response);  
            }  
        }

下面是設置model和modelValue

  1. /** 
         * Expose the model objects in the given map as request attributes. 
         * Names will be taken from the model Map. 
         * This method is suitable for all resources reachable by {@link javax.servlet.RequestDispatcher}. 
         * @param model Map of model objects to expose 
         * @param request current HTTP request 
         */  
        protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {  
            for (Map.Entry<String, Object> entry : model.entrySet()) {  
                String modelName = entry.getKey();  
                Object modelValue = entry.getValue();  
                if (modelValue != null) {  
                    request.setAttribute(modelName, modelValue);  
                    if (logger.isDebugEnabled()) {  
                        logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +  
                                "] to request in view with name '" + getBeanName() + "'");  
                    }  
                }  
                else {  
                    request.removeAttribute(modelName);  
                    if (logger.isDebugEnabled()) {  
                        logger.debug("Removed model object '" + modelName +  
                                "' from request in view with name '" + getBeanName() + "'");  
                    }  
                }  
            }  
        }

第三步,編寫實現Controller的類

  1. public class HomeController implements Controller  
    {  
        private String greeting;  
      
        public String getGreeting()  
        {  
            return greeting;  
        }  
      
        public void setGreeting(String greeting)  
        {  
            this.greeting = greeting;  
        }  
      
        public ModelAndView handleRequest(HttpServletRequest arg0,  
                HttpServletResponse arg1) throws Exception  
        {  
            System.out.println(arg0.getRequestURI());//請求地址  
            return new ModelAndView("home", "message", greeting);  
    //返回一個視圖資源對象,名爲home,model爲message的對象(即上面的exposeModelAsRequestAtrributes方法中使用的request.setAttribute  
        }  
      
    }


第四步,在dispatch-servlet.xml中配置該bean提供給spring web使用。

<bean name="/home.htm" class="com.iss.spring.web.HomeController">  
    <property name="greeting"><value>Hello!This is Training!你好,這裏是訓練營!</value></property>  
</bean>


這裏name將用來匹配請求的資源(默認的使用BeanNameUrlHandlerMapping處理,由bean Name映射 URL),在home.htm請求到達時,

spring將使用實現了Controller接口的HomeController的handleRequest方法來返回映射的視圖資源。


在獲得MoldelAndView對象後,須要根據這個MoldelAndView對象獲得View name而後來解析獲得View對象

  1. /** 
         * Resolve the given view name into a View object (to be rendered). 
         * <p>The default implementations asks all ViewResolvers of this dispatcher. 
         * Can be overridden for custom resolution strategies, potentially based on 
         * specific model attributes or request parameters. 
         * @param viewName the name of the view to resolve 
         * @param model the model to be passed to the view 
         * @param locale the current locale 
         * @param request current HTTP servlet request 
         * @return the View object, or <code>null</code> if none found 
         * @throws Exception if the view cannot be resolved 
         * (typically in case of problems creating an actual View object) 
         * @see ViewResolver#resolveViewName 
         */  
        protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,  
                HttpServletRequest request) throws Exception {  
      
            for (ViewResolver viewResolver : this.viewResolvers) {  
                View view = viewResolver.resolveViewName(viewName, locale);  
                if (view != null) {  
                    return view;  
                }  
            }  
            return null;  
        }


此處須要咱們配置viewResolver bean給spring使用,指明使用哪一個類充當viewResolver並具備什麼屬性

第五步,配置viewResolver bean

  1. <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
            <property name="suffix"><value>.jsp</value></property>  
        </bean>


中間能夠加上prefix或者suffix

這些配置完成後,spring就會根據請求地址以及配置信息,找到視圖資源並作請求轉發操做


總結:整個流程分析下來,其實主要就是作兩個操做,

首先請求信息到達DispatchServlet,Servlet中根據請求信息與配置文件找到映射的視圖資源

而後使用RequestDispatch請求轉發到該視圖資源。

另外,能夠分紅多個bean配置文件,在web.xml中配置載入

  1. <listener>  
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    </listener>  
    <context-param>  
        <param-name>contextConfigLocation</param-name>  
        <param-value>/WEB-INF/dispatch-data.xml,/WEB-INF/dispatch-service.xml</param-value>  
    </context-param>


其中contextConfigLocation這個名字多是匹配FrameworkServlet的setContextConfigLocation方法

也有多是匹配ContextLoaderListener繼承ContextLoader的CONFIG_LOCATION_PARAM

public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
(不肯定,不太瞭解context-param的用法,API上兩個類關於這個變量的說明都相似,也分不太清楚,反正能夠這麼記- -||)


而後配置的viewResolver bean的id爲何要爲viewResolver,下面的是DispatcherServlet中一個靜態字符串說明了一切

public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";

3.2 下面看看看處理請求的流程

圖片上面的Frontcontroller 就至關於Dispatcherservlet

相關文章
相關標籤/搜索