04、SpringMVC执行流程

一、从源码来看

DispatcherServlet核心代码

public class DispatcherServlet extends FrameworkServlet {
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 根据请求对象request获取
        // 这个对象是在每次发送请求时都创建一个,是请求级别的
        // 该对象中描述了本次请求应该执行的拦截器是哪些,顺序是怎样的,要执行的处理器是哪个
        HandlerExecutionChain mappedHandler = getHandler(processedRequest);

        // 根据处理器获取处理器适配器。(底层使用了适配器模式)
        // HandlerAdapter在web服务器启动的时候就创建好了。(启动时创建多个HandlerAdapter放在List集合中)
        // HandlerAdapter有多种类型:
        // RequestMappingHandlerAdapter:用于适配使用注解 @RequestMapping 标记的控制器方法
        // SimpleControllerHandlerAdapter:用于适配实现了 Controller 接口的控制器
        // 注意:此时还没有进行数据绑定(也就是说,表单提交的数据,此时还没有转换为pojo对象。)
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

        // 执行请求对应的所有拦截器中的 preHandle 方法
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
        }

        // 通过处理器适配器调用处理器方法
        // 在调用处理器方法之前会进行数据绑定,将表单提交的数据绑定到处理器方法上。(底层是通过WebDataBinder完成的)
        // 在数据绑定的过程中会使用到消息转换器:HttpMessageConverter
        // 结束后返回ModelAndView对象
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

        //  执行请求对应的所有拦截器中的 postHandle 方法
        mappedHandler.applyPostHandle(processedRequest, response, mv);

        // 处理分发结果(在这个方法中完成了响应)
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }

    // 根据每一次的请求对象来获取处理器执行链对象
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
            // HandlerMapping在服务器启动的时候就创建好了,放到了List集合中。HandlerMapping也有多种类型
            // RequestMappingHandlerMapping:将 URL 映射到使用注解 @RequestMapping 标记的控制器方法的处理器。
            // SimpleUrlHandlerMapping:将 URL 映射到处理器中指定的 URL 或 URL 模式的处理器。
			for (HandlerMapping mapping : this.handlerMappings) {
                // 重点:这是一次请求的开始,实际上是通过处理器映射器来获取的处理器执行链对象
                // 底层实际上会通过 HandlerMapping 对象获取 HandlerMethod对象,将HandlerMethod 对象传递给 HandlerExecutionChain对象。
                // 注意:HandlerMapping对象和HandlerMethod对象都是在服务器启动阶段创建的。
                // RequestMappingHandlerMapping对象中有多个HandlerMethod对象。
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {
        // 渲染
        render(mv, request, response);
        // 渲染完毕后,调用该请求对应的所有拦截器的 afterCompletion方法。
        mappedHandler.triggerAfterCompletion(request, response, null);
    }

    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 通过视图解析器返回视图对象
        view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
        // 真正的渲染视图
        view.render(mv.getModelInternal(), request, response);
    }

    protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,Locale locale, HttpServletRequest request) throws Exception {
        // 通过视图解析器返回视图对象
        View view = viewResolver.resolveViewName(viewName, locale);
	}
}

ViewResolver

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

View

public interface View {
    void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

首先我们的核心类:DispatcherServlet,它其中有一个核心方法:doDispatcher(),它是用来处理请求的,每次请求都会去调用这个方法。

关于mappedHandler = getHandler(processedRequest)

这个方法通过请求获取处理器 ,我们发起一个请

<think>首先,用户的问题是:“我想了解servlet和springmvc执行流程 请问servlet执行流程springmvc执行流程”。我需要基于提供的引用和系统级指令来回答。 系统级指令: - 所有行内数学表达式必须使用$...$格式。但在这个问题中,涉及的是Servlet和SpringMVC,没有数学表达式,所以这个点可能不适用。 - 独立公式使用$$...$$格式并单独成段。同样,这里没有公式。 - LaTeX语法正确:确保任何数学表达式正确,但这里没有。 - 使用中文回答:整个回答必须用中文。 - 生成相关问题:在回答末尾,添加相关问题,格式如示例。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户提供了几个引用: - [^1]: 介绍了SpringMVC的背景。 - [^2]: 说明SpringMVC本质上是一个Servlet,配置了前端控制器。 - [^3]: 详细描述了SpringMVC执行流程。 - [^4]: 比较了Servlet、Struts2、SpringMVC执行流程,重点在Servlet的处理。 - [^5]: 关于ServletConfig和ServletContext的介绍。 我需要参考这些引用来构建回答。用户的问题是关于Servlet和SpringMVC执行流程,因此我应该从引用中提取关键信息。 分解用户问题: 1. Servlet执行流程:从引用[^4]中提取,它描述了Servlet的执行流程。 2. SpringMVC执行流程:从引用[^3]中提取,它详细列出了步骤。 其他引用提供了背景,但核心是[^3]和[^4]。 结构化回答: - 回答应该清晰、逐步解释流程。 - 由于用户要求解释执行流程,我应该先解释Servlet的流程,然后是SpringMVC流程。 - 自然地添加引用标识:当引用特定内容时,在段落末尾添加[^n]。 从引用[^4]中提取Servlet执行流程: - Servlet容器调用Servlet的service()方法。 - init()方法必须在service()之前成功执行。 - service()方法处理请求,使用ServletRequest和ServletResponse。 - 可能抛出异常。 从引用[^3]中提取SpringMVC执行流程: - 这是一个详细的12步流程。 此外,引用[^2]强调SpringMVC本质上是一个Servlet,前端控制器是DispatcherServlet。 引用[^5]提到了ServletConfig和ServletContext,但可能不是核心执行流程。 回答结构: 1. 介绍Servlet执行流程。 2. 介绍SpringMVC执行流程。 3. 可能比较它们,因为用户提到了两者。 4. 确保语言中文。 5. 末尾添加相关问题。 生成相关问题: - 像示例中那样,添加3个左右的相关问题。 - 问题应基于主题,如Servlet的生命周期、SpringMVC的优化等。 完整回答: - 先解释Servlet流程,引用[^4]。 - 然后解释SpringMVC流程,引用[^3]。 - 自然地插入引用。 Servlet执行流程基于引用[^4]: - Servlet容器初始化Servlet时调用init()方法。 - 当请求到来时,容器调用service()方法。 - service()方法使用ServletRequest获取请求信息,ServletResponse设置响应。 - 处理错误时抛出异常。 SpringMVC执行流程基于引用[^3]: 1. 客户端发送请求到DispatcherServlet。 2. HandlerMapping找到匹配的Controller。 3. 返回处理器执行链。 4. DispatcherServlet发送到HandlerAdapter。 5. HandlerAdapter判断Handler是否实现Controller接口。 6. 执行Controller方法。 7. 返回ModelAndView。 8. 传递给ViewResolver解析视图。 9. Web容器渲染视图。 10. 返回响应。 在回答中,简化步骤使其清晰。 最后,添加相关问题。 确保回答真实可靠。 </think>### Servlet 执行流程 Servlet 是 Java Web 应用的核心组件,用于处理 HTTP 请求和响应。其执行流程基于 Java Servlet 规范,主要包括以下步骤: 1. **初始化阶段(init)**:当 Servlet 容器(如 Tomcat)启动时,会调用 Servlet 的 `init()` 方法进行初始化。此方法仅执行一次,用于加载配置参数(如通过 `ServletConfig` 获取初始化参数)和资源准备。如果初始化失败,Servlet 容器会抛出异常,导致 Servlet 不可用[^5]。 2. **请求处理阶段(service)**:当客户端发送 HTTP 请求时,Servlet 容器根据 URL 映射找到匹配的 Servlet,并调用其 `service()` 方法。该方法接收 `ServletRequest` 对象(包含请求信息,如参数、头部)和 `ServletResponse` 对象(用于设置响应内容)。 - 在 `service()` 方法中,Servlet 解析请求、执行业务逻辑(如数据库操作),并生成响应(如 HTML 页面或 JSON 数据)。 - 如果处理期间发生错误,Servlet 可以抛出 `ServletException` 或 `UnavailableException`。前者表示临时错误(容器返回 HTTP 503 响应),后者表示永久错误(容器返回 HTTP 404 响应并调用 `destroy()` 方法释放资源)[^4]。 3. **销毁阶段(destroy)**:当 Servlet 容器关闭或需要回收资源时,调用 `destroy()` 方法进行清理(如关闭数据库连接)。此方法也仅执行一次,之后 Servlet 实例被回收[^4]。 整个流程是同步的,依赖于 Servlet 容器的生命周期管理。Servlet 的本质是单实例多线程模型,每个请求由独立线程处理,但共享同一个 Servlet 实例[^4][^5]。 ### SpringMVC 执行流程 SpringMVC 是基于 Servlet 的 Web 框架,它在底层扩展了 Servlet API,通过前端控制器(`DispatcherServlet`)统一处理请求。其核心流程更模块化和可扩展,以下是详细步骤: 1. **客户端请求到前端控制器**:浏览器发送 HTTP 请求,由 `DispatcherServlet`(在 `web.xml` 中配置为 Servlet)接收所有请求,作为统一的入口点[^2][^3]。 2. **处理器映射(HandlerMapping)**:`DispatcherServlet` 将请求 URL 传递给 `HandlerMapping` 组件,后者查找匹配的 Controller(如基于注解 `@Controller` 的类),并返回一个处理器执行链(包括 Controller 和可能的拦截器)[^3]。 3. **处理器适配(HandlerAdapter)**:`DispatcherServlet` 将处理器执行链传递给 `HandlerAdapter`,后者检查 Controller 是否实现特定接口(如 `Controller` 接口),并调用合适的处理方法(如 `handleRequest()`)[^3]。 4. **Controller 处理**:Controller 执行业务逻辑(如调用 Service 层),完成后返回 `ModelAndView` 对象(包含模型数据和一个视图名称,如 JSP 页面路径)[^3]。 5. **视图解析(ViewResolver)**:`DispatcherServlet` 将 `ModelAndView` 传递给 `ViewResolver`,后者解析视图名称,生成完整的视图路径(如 `/WEB-INF/views/index.jsp`)[^3]。 6. **视图渲染**:`DispatcherServlet` 根据视图路径,委托给 Web 容器(如 Tomcat)进行渲染。容器将模型数据填充到视图模板(如 JSP),生成最终 HTML 响应[^3]。 7. **响应返回**:渲染后的响应通过 `DispatcherServlet` 返回给客户端浏览器[^3]。 SpringMVC 通过这种分层设计,实现了高内聚低耦合,例如 `DispatcherServlet` 作为核心调度器,整合了 HandlerMapping、HandlerAdapter 等组件,简化了开发[^1][^3]。本质上,SpringMVC 是对 Servlet 的封装,它在 Servlet 的 `service()` 方法内部实现了上述流程,从而提供更强大的功能[^2][^4]。 ### 关键区别 - **Servlet**:流程简单直接,开发者需手动处理路由和业务逻辑,适合小型应用。 - **SpringMVC**:流程模块化,通过组件(如 `DispatcherServlet`)自动处理路由和视图,支持拦截器、数据绑定等高级特性,适合大型企业应用[^4][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值