图解SpringMVC工作流程,以及源码分析。
本篇系统地图解和分析Spring MVC的工作流程及其核心源码。这将分为两部分:工作流程图解和核心源码分析。
第一部分:Spring MVC 工作流程图解
Spring MVC的核心是一个围绕DispatcherServlet
设计的“前端控制器”(Front Controller)模式。所有请求都会先经过它,再由它委托给其他组件进行处理。
下图清晰地展示了一个HTTP请求从发起到响应的完整生命周期,以及Spring MVC核心组件在其中扮演的角色:
上述流程可以概括为以下几个关键步骤:
- 发送请求:用户发起一个HTTP请求到web服务器,匹配
DispatcherServlet
的映射路径(如/
)。 - 请求委派:
DispatcherServlet
是流量入口,负责协调所有组件,但它自己不处理业务。 - 查找Handler:
DispatcherServlet
查询一个或多个HandlerMapping
,找到处理该请求的Handler
(通常是Controller
类中的一个方法)和所有匹配的Interceptor
,封装成一个HandlerExecutionChain
。 - 执行拦截器:按顺序执行
HandlerExecutionChain
中所有Interceptor
的preHandle
方法。若某个preHandle
返回false
,则流程中断,直接返回。 - 适配并调用:
DispatcherServlet
通过HandlerAdapter
来实际执行找到的Handler
。适配器模式使得不同类型的Handler
(如@Controller
,Controller
接口,HttpRequestHandler
)都能被统一调用。 - 处理请求:
HandlerAdapter
调用真正的Controller
方法。方法内部执行业务逻辑(调用Service、DAO等),并返回一个ModelAndView
或只是一个视图名称(如"success"
),数据会被添加到Model中。 - 处理返回:
DispatcherServlet
接收到ModelAndView
或可解析的返回值。 - 解析视图:
DispatcherServlet
调用ViewResolver
,根据视图名称(如"success"
)解析出具体的View
对象(如JstlView、ThymeleafView等)。 - 渲染视图:
DispatcherServlet
将Model中的数据传递给View
对象,调用其render()
方法进行视图渲染(如填充HTML模板)。 - 返回响应:渲染完成后,生成最终的HTTP响应内容。
- 事后处理:
DispatcherServlet
会触发Interceptor
的postHandle
和afterCompletion
方法,进行后续处理(如日志记录、资源清理等)。
第二部分:核心源码分析
让我们深入DispatcherServlet
的源码,看看上述流程是如何实现的。核心方法是 doDispatch(HttpServletRequest request, HttpServletResponse response)
。
源码基于Spring Framework 5.x。代码有大量简化,只保留核心逻辑。
1. DispatcherServlet#doDispatch
这是处理请求的核心入口。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null; // 核心对象:处理执行链ModelAndView mv = null;// 1. 查找Handler:获取处理执行链mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {// 如果没有找到Handler,返回404noHandlerFound(processedRequest, response);return;}// 2. 获取HandlerAdapterHandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 3. 执行拦截器的preHandle方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {// 如果preHandle返回false,流程中断return;}// 4. ★ 核心:通过Adapter实际调用Handler(Controller方法)mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// 如果支持异步处理,逻辑会更复杂,这里省略...applyDefaultViewName(processedRequest, mv);// 5. 执行拦截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);// 6. 处理结果:渲染视图或处理异常processDispatchResult(processedRequest, response, mappedHandler, mv, null);
}
2. getHandler()
- 查找HandlerExecutionChain
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {// 遍历所有注册的HandlerMappingfor (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler; // 找到就返回}}}return null;
}
HandlerMapping
的实现类(如RequestMappingHandlerMapping
)会根据请求的URL和@RequestMapping
注解的信息,找到匹配的HandlerMethod
(封装了Controller对象和Method对象)。- 同时,它也会查找所有匹配该请求的
HandlerInterceptor
,一并封装到HandlerExecutionChain
中。
3. ha.handle()
- HandlerAdapter调用Controller
以最常用的RequestMappingHandlerAdapter
为例:
// 在RequestMappingHandlerAdapter中
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ServletWebRequest webRequest = new ServletWebRequest(request, response);WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);// 1. 创建一个Method对象的方法包装器,用于参数解析和方法调用ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);// 2. ★ 设置参数解析器:负责解析Controller方法的每个参数invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);// 3. ★ 设置返回值处理器:负责处理Controller方法的返回值invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);invocableMethod.setDataBinderFactory(binderFactory);// 4. 调用方法并处理返回值invocableMethod.invokeAndHandle(webRequest, mavContainer);// 5. 将结果封装成ModelAndView返回return getModelAndView(mavContainer, modelFactory, webRequest);
}
- 参数解析器 (
ArgumentResolver
):根据参数注解(如@RequestParam
,@RequestBody
)和类型,从HttpServletRequest中提取数据并转换,然后注入到Controller方法的参数中。 - 返回值处理器 (
ReturnValueHandler
):根据返回值的类型和注解(如@ResponseBody
),决定如何处理返回值。是把它当做视图名称,还是直接写入响应体(JSON/XML)。
4. processDispatchResult()
- 处理结果和渲染视图
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {// 处理异常(如果有的话,会转到渲染错误视图)if (exception != null) {mv = processHandlerException(request, response, mappedHandler.getHandler(), exception);}// 开始渲染视图if (mv != null && !mv.wasCleared()) {// ★ 核心:渲染视图render(mv, request, response);} else {// 没有视图,可能是@ResponseBody已经直接写回响应了}// 触发拦截器的afterCompletion方法if (mappedHandler != null) {mappedHandler.triggerAfterCompletion(request, response, null);}
}
5. render()
- 渲染视图
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// 解析视图名称,得到View对象View view;String viewName = mv.getViewName();if (viewName != null) {// ★ 调用ViewResolver解析视图名称view = resolveViewName(viewName, mv.getModelInternal(), locale, request);} else {view = mv.getView(); // 如果ModelAndView里直接包含了View对象}// 调用View的render方法进行渲染view.render(mv.getModelInternal(), request, response);
}
ViewResolver
(如InternalResourceViewResolver
)会将视图名(如"user"
)解析为一个具体的View
对象(如InternalResourceView
,对应JSP)。View
的render()
方法会完成最终的渲染工作,例如对于JSP,会将Model中的数据设置为request的属性,然后执行request.getRequestDispatcher("/WEB-INF/jsp/user.jsp").forward(request, response)
。
总结与关键点
- DispatcherServlet是大脑:它不干活,只负责调度。
- 组件协作:Spring MVC的强大之处在于其高度可配置的组件化设计。每个核心接口(
HandlerMapping
,HandlerAdapter
,ViewResolver
等)都有多种实现,你可以替换或扩展它们来实现自定义行为。 - 适配器模式是核心:
HandlerAdapter
屏蔽了不同Handler
类型的差异,使得框架极其灵活。 - 扩展性:通过
HandlerInterceptor
可以在请求处理的各个关键节点插入自定义逻辑(权限、日志等)。通过自定义ArgumentResolver
和ReturnValueHandler
可以处理任何类型的参数和返回值。
通过结合图解理解流程,再通过源码分析理解实现细节,你就能真正掌握Spring MVC的精髓。建议在IDE中打开Spring源码,沿着doDispatch
方法一步步调试,会有更深刻的体会。