SpirngMVC源码分析

分析过程

  通过 前端控制器源码 分析 SpringMVC 的执行过程

  前端控制器在 web.xml 文件中的配置

<!-- springmvc 前端控制器 -->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器、适配器等等) 
        如果不配置contextConfigLocation,默认加载的是 WEB-INF/servlet名称-servlet.xml (即springmvc-servlet.xml)
    -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/springmvc.xml</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!-- 
        第一种:*.action,访问以.action结尾的由DispatcherServlet进行解析
        第二种: /,所有访问地址都由DispatcherServlet进行解析
            但是对于静态文件的解析,我们需要配置不让DispatcherServlet进行解析
            使用此种方式可以实现Restful风格的URL
        第三种: /* 这种配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由DispatcherServlet
            解析jsp,不能根据jsp页面找到Handler,会报错。
     -->
    <url-pattern>*.action</url-pattern>
</servlet-mapping>

 

 

  第一步:前端控制器接收请求

    调用doDispatch

    

  

  第二步:前端控制器 调用 处理器映射器 查找 Handler

  (1)

  

  (2)映射器根据 request 中的 URL  找到了 Handler,最后返回了执行器链(链中有 Handler)

  

   

  第三步:调用 处理器适配器 执行 Handler,得到执行的结果ModelAndView

  

 

   

  第四步:视图渲染,将 Model 的数据填充到 request 域

  (1)获取 ModelAndView 之后,调用 processDispatchResult()方法

  

  

  (2)processDispatchResult()方法中的 render 方法进行视图渲染

  

   

  (3)render方法进行视图解析,得到 view。view继续调用其 redner()方法。

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Determine locale for request and apply it to the response.
    Locale locale = this.localeResolver.resolveLocale(request);
    response.setLocale(locale);

    View view;
    if (mv.isReference()) {
        // We need to resolve the view name.
        view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException("Could not resolve view with name '" + mv.getViewName()
                    + "' in servlet with name '" + getServletName() + "'");
        }
    } else {
        // No need to lookup: the ModelAndView object contains the actual View object.
        view = mv.getView();
        if (view == null) {
            throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a "
                    + "View object in servlet with name '" + getServletName() + "'");
        }
    }

    // Delegate to the View object for rendering.
    if (logger.isDebugEnabled()) {
        logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
    }
    try {
        view.render(mv.getModelInternal(), request, response);
    } catch (Exception ex) {
        if (logger.isDebugEnabled()) {
            logger.debug(
                    "Error rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'",
                    ex);
        }
        throw ex;
    }
}

 

 

  (4)然后我们发现 render()方法是 View 接口中的一个方法。

  

  

  (5)我们继续向下找,找到实现 View 接口的抽象类 AbstractView。

   抽象类 AbstractView 中,有 render 方法,render 方法中有 renderMergedOutputModel()方法———渲染合并后的输出模型方法

  

  

  

  (6)在 AbstractView 抽象类的子类的 renderMergedOutputModel()方法(以InternalResourceView类为例)中,调用了父类的 exposeModelAsRequestAttributes()这个方法。

 

   

  (7)在 exposeModelAsRequestAttributes()这个方法中,循环遍历 Model ,一个一个填充到 Request 域中(即将模型数据填充 到Request域中)

   

 

  

 

posted @ 2018-12-27 19:47  花咖  阅读(149)  评论(0编辑  收藏  举报