一、概述

学习之后,记下笔记,理清思路。

带着问题去思考:

springMVC接收到用户请求之后,如何工作?

springMVC核心组件有哪些?

哪些是程序员需要编写的部分?

二、SpringMVC工作流程

springmvc腳手架_java

 

 工作流程:

  1. 用户发送请求;
  2. DispatcherSerlvet(前端控制器) 接收请求,调用HandlerMapping;
  3. HandlerMapping(处理器映射器) 去查找处理器Handler(就是Controller),HandlerMapping 返回执行链HandlerExecutionChain(包括Handler对象、拦截器数组)给DispatcherSerlvet;
  4. DispatcherSerlvet调用HandlerAdapter(处理器适配器);
  5. HandlerAdapter去执行Handler;
  6. Handler返回ModelAndView给HandlerAdapter;
  7. HandlerAdapter返回ModelAndView给DispatcherSerlvet;
  8. DispatcherSerlvet调用ViewResolver(视图解析器)进行视图解析;
  9. ViewResolver返回视图对象;
  10. DispatcherSerlvet进行视图渲染
  11. 返回渲染后对象;
  12. 响应请求。

 三、核心组件

前端控制器DispatcherSerlvet

  控制中心,接收请求,转发请求,响应请求

处理器映射器   HandlerMapping

  查找处理器Handler

处理器适配器  HandlerAdapter

  执行处理器Handler

视图解析器  ViewResolver

  解析ModelAndView

处理器Handler    (需要工程师开发)

  Controller

视图View    (需要工程师开发jsp...)

  前端页面

四、源码分析

  1、IDEA创建SpringMVC项目

  参考:

  创建出现的问题:

1

web.xml中出现“element servlet-name is not allow here”,

导致系统启动失败

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">

2

 报错:org.apache.catalina.core.StandardContext.listenerStart Error configuring application listener of class org.springframework.web.context.ContextLoaderListener

 参考:

  创建一个简单的SpringMVC项目,只关注SpringMVC的工作流程。

  2、简单写个接口



@Controller
@RequestMapping("/mvc")
public class HelloWorldController {

    @RequestMapping("helloWorld")
    public String hello(){
        return "helloWorld";
    }
}



  3、分析DispatcherServlet

springmvc腳手架_前端_02

思路:DispatcherServlet继承FrameworkServlet,就是servlet,

  servlet分:初始化,处理方法,销毁方法

  核心就是service,

  (下图是FrameworkServlet中的service方法)

springmvc腳手架_ViewUI_03

  再看关键的processRequest方法

 

springmvc腳手架_ViewUI_04

点进去一看,是个抽象方法

springmvc腳手架_ViewUI_05

那DispatcherServlet肯定重写了该方法



//DispatcherServlet.java
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if(this.logger.isDebugEnabled()) {
            String attributesSnapshot = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()?" resumed":"";
            this.logger.debug("DispatcherServlet with name \'" + this.getServletName() + "\'" + attributesSnapshot + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
        }

        HashMap attributesSnapshot1 = null;
        if(WebUtils.isIncludeRequest(request)) {
            attributesSnapshot1 = new HashMap();
            Enumeration inputFlashMap = request.getAttributeNames();

            label108:
            while(true) {
                String attrName;
                do {
                    if(!inputFlashMap.hasMoreElements()) {
                        break label108;
                    }

                    attrName = (String)inputFlashMap.nextElement();
                } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

                attributesSnapshot1.put(attrName, request.getAttribute(attrName));
            }
        }

        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
        FlashMap inputFlashMap1 = this.flashMapManager.retrieveAndUpdate(request, response);
        if(inputFlashMap1 != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap1));
        }

        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

        try {
            this.doDispatch(request, response);   //关键方法
        } finally {
            if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot1 != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot1);
            }

        }

    }



再看doDispatch,做了啥,看见了关键词getHandler、getHandlerAdapter

springmvc腳手架_web.xml_06

getHandler,返回  HandlerExecutionChain

springmvc腳手架_springmvc腳手架_07

getHandlerAdapter,返回  HandlerAdapter

springmvc腳手架_前端_08

 

  4、调用getHandler,获取HandlerExecutionChain

 在上面的两个方法上打断点,

this.handlerMappings  有三个元素

springmvc腳手架_前端_09

this.handlerMappings有三种类型,根据request请求使用不同的HandlerMapping

  1. RequestMappingHandlerMapping (支持带@RequestMapping注释的方法)
  2. BeanNameUrlHandlerMapping
  3. SimpleUrlHandlerMapping (维护URI路径模式到处理程序的显式注册)。

springmvc腳手架_ViewUI_10

返回handler(一个HandlerExecutionChain对象,包含了处理器controller和一个或多个拦截器),对应DispatcherServlet中的mappedHandler

  4、调用getHandlerAdapter,获取HandlerAdapter

springmvc腳手架_springmvc腳手架_11

 

 

springmvc腳手架_springmvc腳手架_12

this.handlerAdapters有三种

  1. HttpRequestHandlerAdapter
  2. SimpleControllerHandlerAdapter
  3. RequestMappingHandlerAdapter

遍历所有类型,判断是否支持当前处理器handler

springmvc腳手架_前端_13

匹配RequestMappingHandlerAdapter,返回

 

springmvc腳手架_springmvc腳手架_14

进行到这一步,真正执行我们编写的处理器(Controller)

 

springmvc腳手架_ViewUI_15

springmvc腳手架_前端_16

返回ModelAndView

springmvc腳手架_java_17

 后面还有视图解析。