知道大家写后端接口的时候,有没有好奇过,我们浏览器发一个请求,给到 SpringMVC 项目里面,它内部到底经过了哪些步骤,最后把结果又返回给浏览器。DispatcherServlet、HandlerMapping、HandlerAdapter、ViewResolver,这一堆名词看着头大却又不理解。今天我们用很通俗的方式讲一遍 SpringMVC 完整执行流程。其实SpringMVC工作原理根本没有想象的复杂!
完整的请求执行流程

1. 浏览器发起请求,请求抵达 DispatcherServlet
用户在浏览器输入地址,或者前端发 ajax 请求,http 请求过来,首先会被 DispatcherServlet 拦截接收。所有请求都汇集到这,它不直接处理业务,专门做调度分发,相当于公司的前台,收到外来访客,不会自己干活,负责往下派活。
(补充:DispatcherServlet,前端控制器,整个 SpringMVC 的大总管,所有请求第一个找的就是它。)
2.DispatcherServlet 调用 HandlerMapping(处理器映射器)
大总管拿到请求之后,得知道这个请求该交给哪个 Controller 里面哪个方法去处理。于是去找 HandlerMapping。HandlerMapping 里面存好地址和方法的对应关系,比如/user/list对应 UserController 里的 list () 方法。它根据请求的 URL 去找匹配的处理器,找到之后,返回一个 Handler 执行链(里面包含我们写的 Controller 方法,还有配套拦截器),交还给 DispatcherServlet。
(简单说:HandlerMapping 的工作 ------ 查地址,找到该调用哪个 Controller。)
3.DispatcherServlet 调用 HandlerAdapter(处理器适配器)
拿到 Controller 的信息之后,DispatcherServlet 不会直接调用 Controller 方法。为什么搞个适配器?因为处理器的类型可能不止 Controller 这一种,适配器做适配,统一调用规则。 HandlerAdapter 拿到 handler 信息,它负责真正执行我们 Controller 里面写的业务方法 。 这里还会做参数绑定:把前端传过来的请求参数,封装成我们 Controller 方法上的形参,注意@RequestParam、@RequestBody 这些注解就是在这里生效。参数校验也发生在这一步。
4. 执行 Controller 中的自定义业务代码
适配器调用 Controller 里面的业务方法,咱们写的查询、新增逻辑在这里跑。 Controller 执行完之后,不会直接返回页面 / 数据,返回一个ModelAndView对象。)
- 如果是传统页面开发:Model 存数据,View 存要跳转的页面名字;
- 如果现在前后端分离接口,加了
@ResponseBody,直接把数据写入响应,就不走页面解析那一步。
5.HandlerAdapter 将 ModelAndView 返回给 DispatcherServlet
业务方法跑完,结果包装成 ModelAndView 交回大总管 DispatcherServlet。
(小插曲:如果加了 @ResponseBody,在这一步就会通过消息转换器,把对象转成 JSON 字符串,直接写回响应,后面视图解析就跳过。现在做后端开发大部分都是这个(B/S前后端分离)模式。)
6.DispatcherServlet 调用 ViewResolver(视图解析器)
如果不是返回 JSON,是要跳转页面,就走到视图解析器 ViewResolver。 它拿到 View 名字,拼接前缀后缀,把逻辑视图名转成真实物理视图,比如"user/list"拼接成/WEB-INF/jsp/user/list.jsp。解析完成,返回真正的 View 对象。
7. 视图渲染,向浏览器返回最终响应
拿到真实 View 之后,做视图渲染,把 Model 里面存放的数据填充到 jsp 页面里面,生成最终的 html 内容。 最后 DispatcherServlet 把最终的响应结果返回浏览器,一次完整请求到此结束。
总结:
总的来说 SpringMVC 把一次 HTTP 请求拆分成多个组件分工协作,每个组件各司其职、解耦配合,弄懂这套流程,再写接口时就不再只停留在调用 API 的表层,能够看透框架背后到底在帮我们做哪些事。