SpringMVC 是Java Web开发中最经典的框架之一,但你是否真正理解它的内部运行机制?当用户在浏览器输入一个URL时,SpringMVC是如何一步步处理请求并返回结果的?本文从源码层面解析SpringMVC的核心流程,用大白话+代码示例,带你彻底搞懂背后的设计思想!
一、SpringMVC工作流程总览
先看一张经典流程图:
核心步骤:
-
用户发送请求 → 2. DispatcherServlet接收请求 → 3. HandlerMapping找Controller → 4. HandlerAdapter调用Controller方法 → 5. Controller处理请求 → 6. 返回ModelAndView → 7. ViewResolver解析视图 → 8. 渲染视图并返回响应
二、源码级分步解析
1. DispatcherServlet:请求的“总调度员”
核心作用:所有HTTP请求的入口,负责协调各组件工作。
源码入口:DispatcherServlet
的doDispatch
方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. 获取处理器映射(HandlerMapping)
HandlerExecutionChain mappedHandler = getHandler(request);
// 2. 获取处理器适配器(HandlerAdapter)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 调用Controller方法处理请求
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
// 4. 解析视图并渲染
processDispatchResult(request, response, mappedHandler, mv, dispatchException);
}
2. HandlerMapping:找到对应的Controller
核心作用:根据请求的URL,找到对应的Controller类和方法。
常见实现:RequestMappingHandlerMapping
(基于注解的映射)。
源码解析:
// RequestMappingHandlerMapping 中查找匹配的HandlerMethod
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 查找匹配的Controller方法
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return handlerMethod;
}
3. HandlerAdapter:调用Controller方法
核心作用:适配不同的Controller类型(如基于注解的@Controller
、传统的Controller
接口)。
常见实现:RequestMappingHandlerAdapter
(处理@RequestMapping
方法)。
源码解析:
// RequestMappingHandlerAdapter 调用Controller方法
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 反射调用Controller方法
Object returnValue = invokeHandlerMethod(request, response, handlerMethod);
// 封装结果为ModelAndView
return getModelAndView(mavContainer, modelFactory, request);
}
4. Controller处理请求
核心作用:执行业务逻辑,返回数据或视图。
示例代码:
@Controller
public class UserController {
@GetMapping("/user")
public String getUser(Model model) {
model.addAttribute("user", new User("Spring"));
return "user"; // 返回视图名
}
}
5. ViewResolver:解析视图
核心作用:将Controller返回的视图名(如"user"
)解析为具体的视图对象(如JSP、Thymeleaf模板)。
常见实现:InternalResourceViewResolver
(解析JSP)。
源码解析:
j
// InternalResourceViewResolver 解析视图名
protected View createView(String viewName, Locale locale) throws Exception {
// 拼接JSP路径(如 "/WEB-INF/views/user.jsp")
String url = getPrefix() + viewName + getSuffix();
return new InternalResourceView(url);
}
6. 视图渲染
核心作用:将模型数据填充到视图中,生成最终的HTML响应。
源码解析:
// AbstractView 渲染视图
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) {
// 将Model数据暴露到Request属性中
exposeModelAsRequestAttributes(model, request);
// 转发到JSP页面
request.getRequestDispatcher(url).forward(request, response);
}
三、核心组件协作流程图解
用户请求 → DispatcherServlet → HandlerMapping
→ HandlerAdapter → Controller → ModelAndView
→ ViewResolver → View → 响应
四、常见问题与避坑指南
问题1:为什么Controller方法返回String,就能跳转到页面?
答案:
-
返回的String会被
ViewResolver
解析为具体视图路径(如JSP)。 -
例如返回
"user"
,InternalResourceViewResolver
会拼接为/WEB-INF/views/user.jsp
。
问题2:如何实现RESTful接口返回JSON?
答案:
-
使用
@ResponseBody
注解,配合HttpMessageConverter
(如Jackson)将返回值转为JSON。
j
@GetMapping("/api/user")
@ResponseBody
public User getUser() {
return new User("Spring");
}
问题3:HandlerMapping和HandlerAdapter的区别?
答案:
-
HandlerMapping:负责找哪个Controller处理请求。
-
HandlerAdapter:负责实际调用Controller的方法。
五、SpringMVC的扩展点
-
拦截器(Interceptor)
实现HandlerInterceptor
接口,在请求处理前后插入逻辑(如权限校验)。 -
自定义ViewResolver
实现ViewResolver
接口,支持自定义视图类型(如PDF导出)。 -
异常处理器(@ExceptionHandler)
统一处理Controller抛出的异常。
六、总结
-
核心流程:DispatcherServlet协调各组件,从请求到响应的完整链路。
-
关键组件:HandlerMapping、HandlerAdapter、ViewResolver各司其职。
-
扩展能力:通过拦截器、自定义视图等灵活扩展功能。