SpringMVC运行流程分析

一、运行流程图

下面是 SpringMVC 运行流程的分析图,包括了拦截器的调用过程,目标资源的处理以及异常处理。
这里写图片描述

二、运行流程中的相关组件

在上面的流程图中有几个比较重要的组件,下面大概描述一下其对应的作用。
这里写图片描述
DispatcherServlet:用于接收请求,响应结果。相当于转发器,中央处理器。用户请求到达DispatcherServlet,它是整个流程控制中心,由它调用其它组件来处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。

HandlerMapping:负责根据用户请求的URL找到handler路由处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

HandlerAdapter:按照特定的规则帮助DispatcherServlet去执行handler。比如调用带注释的控制器需要解析注释等。

ViewResolver:提供视图名称和实际视图之间的映射。ViewResolver首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

三、源码分析

运行流程的执行通过DispatcherServlet中的doDispatch(HttpServletRequest request, HttpServletResponse response)方法进行统一的调用与管理。

PS:这里只能给大家提供一个调试代码的方法,其中有很多细节这里就不再一一描述了。

下面贴出 SpringMVC 4.3.16.RELEASE 版本中 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 {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // 在getHandler方法中通过HandlerMapping获得HandlerExecutionChain对象
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // 获得HandlerAdapter对象
                HandlerAdapter ha = 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 (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                // 调用拦截器的preHandle()方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // 调用目标路由方法得到ModelAndView对象
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                applyDefaultViewName(processedRequest, mv);
                // 调用拦截器的postHandle()方法  
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            /**
            * 在processDispatchResult() 方法中首先会判断是否存在异常,然后完成试图的渲染,
            * 并调用拦截器的afterCompletion()方法
            */
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

doDispatch(HttpServletRequest request, HttpServletResponse response)方法调用了很多其他的方法来保证运行流程正确的执行,对于这些方法具体做了什么,需要你自己通过 DEBUG 的方式去了解。

<think>好的,我现在需要帮用户了解Servlet和SpringMVC的执行流程。首先,我得回顾一下用户的问题,确认他们需要详细的执行步骤,可能还希望两者的对比或关联。用户提到“执行流程详解”,所以需要分步骤解释,每个环节的作用。 先处理Servlet部分。Servlet是Java Web的基础,处理HTTP请求的核心。它的执行流程大致是:容器接收请求,创建请求和响应对象,调用service方法,根据方法类型分发到doGet或doPost,最后生成响应。这里需要详细说明每个步骤,比如容器的角色,service方法的作用,以及生命周期管理。 接下来是SpringMVC,用户可能已经知道Servlet,现在想了解SpringMVC如何在此基础上构建更复杂的流程。根据提供的引用,特别是引用[1]和[3],SpringMVC的核心是DispatcherServlet,需要详细说明它的处理过程,包括HandlerMapping、HandlerAdapter、ViewResolver等组件的作用。需要结合引用中的流程图,比如请求如何被DispatcherServlet接收,如何找到处理器,执行拦截器,处理返回结果,解析视图等。 需要注意用户提供的引用中有关于配置的内容,比如引用[4]提到的视图解析器配置,但用户现在可能更关注执行流程而不是配置,所以可以简要提及组件,但重点放在流程上。同时,用户可能希望了解两者的区别,比如SpringMVC如何扩展Servlet的功能,比如通过前端控制器模式集中处理请求,而Servlet更直接。 另外,用户要求生成相关问题,可能需要围绕执行流程的细节、组件作用、对比、异常处理等方面提问。例如,Servlet的生命周期,SpringMVC的视图解析过程,或者两者在处理请求时的异同。 需要确保回答结构清晰,分点列出,使用中文,并且正确应用LaTeX格式,比如行内公式用$...$,独立公式用$$...$$。不过在流程描述中可能用不到太多数学公式,但如果有涉及变量或技术术语,需注意格式。 最后,检查引用是否正确应用,如引用[1]提到SpringMVC的执行流程图,引用[3]提到视图解析的具体方法,这些需要自然地插入到相关部分的末尾。例如,在讲解SpringMVC的视图解析时,可以引用[3]中的代码片段说明processDispatchResult方法的作用。 总结步骤: 1. 分两部分详细说明Servlet和SpringMVC的执行流程。 2. 每个流程分步骤解释,结合提供的引用内容。 3. 对比两者的异同,帮助用户理解关系。 4. 生成相关问题,覆盖流程细节、组件作用、实际应用等。</think>### Servlet执行流程详解 1. **请求接收**:Web服务器(如Tomcat)接收到HTTP请求后,创建`ServletRequest`和`ServletResponse`对象[^1]。 2. **Servlet初始化**:若Servlet实例未创建,容器调用其`init()`方法初始化。 3. **请求处理**:容器调用Servlet的`service()`方法,根据请求类型(GET/POST)分发到`doGet()`或`doPost()`方法。 4. **生成响应**:业务逻辑处理后,通过`ServletResponse`写入响应数据。 5. **资源释放**:容器调用`destroy()`方法释放资源(仅一次,在Servlet生命周期结束时)。 ### SpringMVC执行流程分析 1. **请求分发**:所有请求由`DispatcherServlet`(前端控制器)统一接收[^1]。 2. **处理器映射**:通过`HandlerMapping`解析请求URL,找到对应的控制器(Controller)[^2]。 3. **处理器适配**:`HandlerAdapter`调用Controller的具体方法,处理请求参数并执行业务逻辑[^2]。 4. **结果处理**:Controller返回`ModelAndView`对象,包含模型数据和视图名称。 5. **视图解析**:`ViewResolver`将逻辑视图名解析为具体视图(如JSP),并渲染数据到客户端[^3][^4]。 6. **拦截器扩展**:流程中穿插拦截器(`preHandle`、`postHandle`、`afterCompletion`),用于权限校验或日志记录[^1]。 ### 核心区别 - **Servlet**:直接处理请求,需手动管理线程、参数解析等。 - **SpringMVC**:通过组件化设计(如`DispatcherServlet`、`HandlerMapping`)解耦,支持声明式开发[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值