Spring MVC之 DispatcherServlet

SpringMVC之 DispatcherServlet

 

web.xml

 

<?xml version="1.0" encoding="UTF-8"?>  
<web-app version="2.5"   
    xmlns="http://java.sun.com/xml/ns/javaee"   
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  <display-name></display-name>   
  <welcome-file-list>  
    <welcome-file>index.jsp</welcome-file>  
  </welcome-file-list>  
  <servlet>  
              <servlet-name>springMVC</servlet-name>  
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
              <init-param>  
                      <param-name>contextConfigLocation</param-name>  
                      <param-value>classpath*:springController.xml</param-value>  
              </init-param>  
  </servlet>  
    
  <servlet-mapping>  
                <servlet-name>springMVC</servlet-name>  
                <url-pattern>/</url-pattern>  
  </servlet-mapping>  
  
<span style="color:#ff6666;"> <context-param>  
                 <param-name>contextConfigLocation</param-name>  
                 <param-value>classpath*:springController.xml</param-value>  
  </context-param>   
  <listener>  
                 <listener-class>  
                       org.springframework.web.context.ContextLoaderListener  
                 </listener-class>  
  </listener>  
  
</web-app></span>  

 

 

1. DispatcherServlet: defines the context configuration file of Spring MVC

2. ContextLoaderListene: defines the context configuration file of the applicationContext.

 

In fact, these two configuration files can be put together, but the responsibilities will be clearer when they are separated.

 

 

Diagram of the relationship between the initial context of DispatcherServlet and the initial context of ContextLoaderListener



 

Notice:

 

1. The beans loaded by the initial context of DispatcherServlet are beans that are valid for SpringMVC, such as HandlerMapping, HandlerAdapter, ViewResoler.

 

2. The initial context of ContextLoaderListener is a bean shared by the entire application, such as DAO, serivce, etc.

 

3. The initial context of DispatcherServlet will inherit the context of ContextLoaderListener.

 

 

 

Initialization of DispatcherServlet

 

When we start the server, the program just initializes the context of the DispatcherServlet, but has not initialized the DispatcherServlet, just like when we go to buy a desktop computer, and what we buy and put in a box includes a monitor, a chassis, a motherboard, a graphics card, etc. If you want to To use a computer, we have to assemble the computer. Initialization is like assembling the HandlerMapping, HandlerAdapter, and ViewResoler configured in our configuration file, and then we can actually use it. Let's take a look at the source code of DispatcherServlet initialization

 

 

protected void initStrategies(ApplicationContext context) {  
        initMultipartResolver(context);  
        initLocaleResolver(context);  
        initThemeResolver(context);  
        initHandlerMappings(context);  
        initHandlerAdapters(context);  
        initHandlerExceptionResolvers(context);  
        initRequestToViewNameTranslator(context);  
        initViewResolvers(context);  
    }  

 

 

 

 

DispatcherServlet的工作流程



 

Dispatcher中的doDispatcher源码

 

//前端控制器分派方法  
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
        HttpServletRequest processedRequest = request;  
        HandlerExecutionChain mappedHandler = null;  
        int interceptorIndex = -1;  
  
        try {  
            ModelAndView mv;  
            boolean errorView = false;  
  
            try {  
                   //检查是否是请求是否是multipart(如文件上传),如果是将通过MultipartResolver解析  
                processedRequest = checkMultipart(request);  
                   //步骤2、请求到处理器(页面控制器)的映射,通过HandlerMapping进行映射  
                mappedHandler = getHandler(processedRequest, false);  
                if (mappedHandler == null || mappedHandler.getHandler() == null) {  
                    noHandlerFound(processedRequest, response);  
                    return;  
                }  
                   //步骤3、处理器适配,即将我们的处理器包装成相应的适配器(从而支持多种类型的处理器)  
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  
                  // 304 Not Modified缓存支持  
                //此处省略具体代码  
  
                // 执行处理器相关的拦截器的预处理(HandlerInterceptor.preHandle)  
                //此处省略具体代码  
  
                // 步骤4、由适配器执行处理器(调用处理器相应功能处理方法)  
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  
                // Do we need view name translation?  
                if (mv != null && !mv.hasView()) {  
                    mv.setViewName(getDefaultViewName(request));  
                }  
  
                // 执行处理器相关的拦截器的后处理(HandlerInterceptor.postHandle)  
                //此处省略具体代码  
            }  
            catch (ModelAndViewDefiningException ex) {  
                logger.debug("ModelAndViewDefiningException encountered", ex);  
                mv = ex.getModelAndView();  
            }  
            catch (Exception ex) {  
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);  
                mv = processHandlerException(processedRequest, response, handler, ex);  
                errorView = (mv != null);  
            }  
  
            //步骤5 步骤6、解析视图并进行视图的渲染  
//步骤5 由ViewResolver解析View(viewResolver.resolveViewName(viewName, locale))  
//步骤6 视图在渲染时会把Model传入(view.render(mv.getModelInternal(), request, response);)  
            if (mv != null && !mv.wasCleared()) {  
                render(mv, processedRequest, response);  
                if (errorView) {  
                    WebUtils.clearErrorRequestAttributes(request);  
                }  
            }  
            else {  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +  
                            "': assuming HandlerAdapter completed request handling");  
                }  
            }  
  
            // 执行处理器相关的拦截器的完成后处理(HandlerInterceptor.afterCompletion)  
            //此处省略具体代码  
  
  
        catch (Exception ex) {  
            // Trigger after-completion for thrown exception.  
            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
            throw ex;  
        }  
        catch (Error err) {  
            ServletException ex = new NestedServletException("Handler processing failed", err);  
            // Trigger after-completion for thrown exception.  
            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
            throw ex;  
        }  
  
        finally {  
            // Clean up any resources used by a multipart request.  
            if (processedRequest != request) {  
                cleanupMultipart(processedRequest);  
            }  
        }  
    }  

 

 

 

核心架构的具体流程步骤如下:

 

1、  首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;

 

2、  DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;

 

3、  DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;

 

4、  HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);

 

5、  ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;

 

6、  View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;

 

7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。

 

此处我们只是讲了核心流程,没有考虑拦截器、本地解析、文件上传解析等。

 

 

 

 

参考:

http://blog.csdn.net/wangbiao007/article/details/50510274

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326496563&siteId=291194637