SpringMVC源码解析系列(2)之Spring MVC处理请求的执行流程

重要的前置知识:

Spring MVC中有几大组件,帮助Spring MVC实现请求的处理工作:

前端控制器:DispatcherServlet

作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求

配置:前端控制器DispatcherServlet由Spring提供,需要我们在web.xml配置文件中手动配置(可以采用注解开发,但也需要手动配置)

处理器映射器:HandlerMapping

作用:根据请求的url、param等信息查找Handler,即控制器方法

处理器适配器:HandlerAdapter

作用:通过HandlerAdapter对处理器(控制器方法)进行执行

配置:通过在SpringMVC.xml文件中配置<mvc:annotation-driven/>标签Spring可以自动的帮我们创建RequestMappingHandlerMapping(处理映射器)和

RequestMappingHandlerAdapter( 处理适配器)。

视图解析器:ViewResolver

作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、 RedirectView

配置:视图解析器的种类有很多,需要用户根据自己的需求,创建相应的试图解析器,将其交由IOC容器进行管理

处理器:Handler

作用:对具体的用户请求进行处理,就是控制器方法

视图:View

作用:将模型数据通过页面展示给用户


1.tomcat接收到请求,会将请求封装成HttpServletRequest

2.然后选择路径匹配的Servlet调用它的doGet()或者doPost()方法,并将HttpServletRequest作为参数传递过去,因为我们配置了前端控制器,所以tomcat会调用DispatcherServlet的doGet()或者doPost()方法,由于DispatcherServlet没有重写上述方法,所以会调用父类FrameworkServlet的方法

FrameworkServlet

protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 调用自己的processRequest()方法
    this.processRequest(request, response);
}
​
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        LocaleContext localeContext = this.buildLocaleContext(request);
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
        this.initContextHolders(request, localeContext, requestAttributes);
​
        try {
            // 执行服务,doService()是一个抽象方法,在DispatcherServlet中进行了重写
            this.doService(request, response);
        } catch (IOException | ServletException var16) {
            failureCause = var16;
            throw var16;
        } catch (Throwable var17) {
            failureCause = var17;
            throw new NestedServletException("Request processing failed", var17);
        } finally {
            this.resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();
            }
​
            this.logResult(request, response, (Throwable)failureCause, asyncManager);
            this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
        }
​
    }

DispatcherServlet#doService

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    this.logRequest(request);
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap();
        Enumeration attrNames = request.getAttributeNames();
​
        label120:
        while(true) {
            String attrName;
            do {
                if (!attrNames.hasMoreElements()) {
                    break label120;
                }
​
                attrName = (String)attrNames.nextElement();
            } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
​
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
        }
    }
    // 将servlet的一些属性信息放入请求域
    // 将当前servlet的子webapplicationcontext放入请求域中
    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());
    if (this.flashMapManager != null) {
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
​
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }
​
    RequestPath requestPath = null;
    if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
        requestPath = ServletRequestPathUtils.parseAndCache(request);
    }
​
    try {
        // 进行请求的分派(处理请求)
        this.doDispatch(request, response);
    } finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
            this.restoreAttributesAfterInclude(request, attributesSnapshot);
        }
​
        if (requestPath != null) {
            ServletRequestPathUtils.clearParsedRequestPath(request);
        }
​
    }
​
}

DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
​
    try {
        try {
            ModelAndView mv = null;
            Object dispatchException = null;
​
            try {
                processedRequest = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                /**
                    获取处理器的调用链:               
                    mappedHandler:调用链
                    包含handler、interceptorList、interceptorIndex
                    handler:浏览器发送的请求所匹配的控制器方法
                    interceptorList:处理控制器方法的所有拦截器集合
                    interceptorIndex:拦截器索引,控制拦截器afterCompletion()的执行
                **/
                // 会循换遍历全部的处理器映射器,利用处理器映射器找到能与当前请求相匹配的handler,找到了直接返回,找不到遍历下一个处理器映射器,继续getHandler,都找不到返回null,
                /**
                如果我们配置了  <mvc:annotation-driven/>标签,Spring会注册RequestMappingHandlerMapping处理器映射器,那默认情况下就存在三个处理器映射器
                1.RequestMappingHandlerMapping-->帮我们匹配请求uri和检测到的所有uri Map(通过@RequestMapping注解设置的uri),以及遍历获取匹配的拦截器,封装成 HandlerExecutionChain返回
                2.BeanNameUrlHandlerMapping
                3.SimpleUrlHandlerMapping它继承了AbstractUrlHandlerMapping,其中有一个属性handlerMap,里面存放了我们通过<mvc:default-servlet-handler>标签,注册的DefaultServletHttpRequestHandler,它会作为handler,然后去遍历获取匹配的拦截器,封装成 HandlerExecutionChain返回
                
                **/
                mappedHandler = this.getHandler(processedRequest);
                if (mappedHandler == null) {
                    this.noHandlerFound(processedRequest, response);
                    return;
                }
                // 获取处理器适配器:
                // 会遍历全部的处理器适配器,找到支持当前处理器的处理器适配器
                HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
        // 调用前置处理器:遍历处理器调用链中的拦截器列表,调用每个拦截器的preHandler()方法
               /**
               interceptorIndex初始为-1,每调用一次preHandle()方法,并且preHandler()返回值为true,就会将interceptorIndex加1,实际上它记录的就是刚刚遍历过的返回值为true的拦截器索引,
              1. 如果preHandler()返回false,interceptorIndex=当前返回false的拦截器的前一个拦截器的索引, 并会从interceptorIndex对应的索引开始,向前遍历拦截器,调用他们的afterCompletion方法,
               2.如果没有拦截器的preHandler()返回false,interceptorIndex=最后一个拦截器的索引,直接返回true
              总结:顺序调用拦截器的preHandler()方法,逆序调用之前遍历过的拦截器的afterCompletion()方法
               **/
         // 如果返回false直接结束该方法,不再执行,返回true继续执行
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
        // 处理请求,调用控制器方法获取模型和视图对象
                /**
                1.获取控制器方法中的参数,将解析到的相对应的参数值,传入方法,进行调用
                2.创建modelandview对象,将model封装进mav中
                3.获取返回的视图名称,放入mav
                4.返回mav           
                **/
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
​
                this.applyDefaultViewName(processedRequest, mv);
                // 倒序调用后置处理器
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var20) {
                dispatchException = var20;
            } catch (Throwable var21) {
                dispatchException = new NestedServletException("Handler dispatch failed", var21);
            }
            // 后续处理,处理模型数据和渲染视图
            /**
            1.如果前面抛出了异常,异常被捕获,并且,将异常对象对象赋值给dispatchException,所以在此后续处理方法中会判断是否出现了异常,如果出现异常,就遍历异常解析器,调用它们的resolveException()方法,并重新创建异常的mav,返回
            2.调用render()方法,进行视图的渲染
                ①遍历视图解析器,解析视图名称(拼接前缀和后缀),创建视图对象
                ②模板引擎解析视图对象
                ③设置响应数据到response中(reaponse的输出流的buffer中)
            3.执行拦截器链的afterCompletion(…)方法,倒序执行
            **/
            this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
        } catch (Exception var22) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
        } catch (Throwable var23) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
        }
​
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
        }
​
    }
}

看下默认情况下的处理器映射器:

拦截器链中的内容:

modelAndView中的内容:

响应数据的内容:

总结:

1) 用户向服务器发送请求,tomcat调用Servlet(DispatcherServlet)的doXXx(..)方法,传入请求和响应对象。最终会调用到doDispatch方法

2) 在doDispatch方法会调用getHandler()方法,获取处理器执行链,处理器执行链包含三部分内容(handler、interceptorList、interceptorIndex)

a)首先,遍历处理器映射器,调用处理器映射器的getHandler()方法,获取处理器执行链:

i)在处理器映射器的getHandler()方法中会调用getHandlerInternal()方法,去解析请求的URL获取 资源标识符URI(URI-web项目的标识符),对于不同的处理器映射器会去不同的Map中匹配路径,获取相对应的处理器(构造器方法对象)

1.RequestMappingHandlerMapping会去 AbstractHandlerMethodMapping.MappingRegistry#pathLookup(内部存放着全部请求映射路径)中获取

2.SimpleUrlHandlerMapping会去AbstractUrlHandlerMapping#handlerMap(内部存放着我们我们通过<mvc:default-servlet-handler>标签注册的默认servletHandler)中获取

ii)如果获取到了,返回获取到的处理器对象。接着获取路径匹配的拦截器列表,封装成HandlerExecutionChain返回

ii)如果getHandlerInternal()方法没有获取到,就去获取默认的处理器(默认为null),也获取不到,直接返回null;获取到了接着获取路径匹配的拦截器列表,封装成HandlerExecutionChain返回

b)如果,处理器映射器的getHandler()方法返回null,继续遍历下一个处理器映射器,调用它的getHandler()方法;如果不为null,就直接返回。(也就是说只要handler为null,处理器执行链就为null,就会直接报404

3)如果返回的处理器执行链为null,控制台报映射查找不到,客户端展示404错误

4) 如果返回的处理器执行链不为null,DispatcherServlet 根据获得的Handler,调用getHandlerAdapter()方法,选择一个合适的HandlerAdapter。

5) 如果成功获得HandlerAdapter,此时将开始遍历执行拦截器的preHandler(…)方法【正向】,如果有 preHandler(…)方法返回false,就逆向调用已经遍历过的拦截器的afterCompletion(…)方法,返回false,结束dispatcher()

6) 如果全部拦截器的preHandler(…)方法都返回true,会调用handle()方法,去处理请求,获取modelandview对象,在handle()方法中会调用处理器的handleRequest()方法,对于不同的处理器,有不同的处理逻辑:

a)如果是因为在请求映射Map中没有匹配的路径,而使用了默认的ServletHandler,在他的handleRequest()方法内部,会进行请求的转发,解析静态资源(js、html、jsp)(直接去webapp目录下面找),如果没有找到对应的静态资源,也会报404错误,找到了就直接响应界面,返回null。

b)如果使用控制器方法作为处理器,提取request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。 在填充Handler的入参过程中,根据你的参数配置,Spring将帮你做一些额外的工作:

i) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定 的响应信息

ii) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

iii) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

iiii) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

7) Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象(可能为null,因为使用默认的ServletHandler)。

8) 此时将开始执行拦截器的postHandle(...)方法【逆向】。

9) 接着调用processDispatchResult()方法处理分发结果

a)首先会判断是否存在异常,如果存在异常,则执行 HandlerExceptionResolver异常解析器的processHandlerException()方法,进行异常处理,创建新的ModelAndView对象返回

b)如果ModelAndView不为null,渲染视图,选择一个适合的ViewResolver进行视图解析,创建视图对象,模板引擎解析视图对象,设置输出流到响应对象中。

c)渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】

10) 将渲染结果返回给客户端。

如有问题欢迎指正......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值