Spring MVC 执行流程及核心组件总结
Spring MVC 是一个基于请求驱动的 Web 框架,以下是从客户端请求到响应返回的完整执行流程,按照组件的执行顺序逐步讲解,并涵盖每个组件的功能与使用实例。
Spring MVC 的主要功能
-
请求分发与处理:
- 使用
DispatcherServlet
作为前端控制器,统一接收和分发客户端的请求,解耦请求的接收和处理。
- 使用
-
视图渲染:
- 支持通过
ViewResolver
和视图模板引擎(如 JSP、Thymeleaf)将模型数据渲染为 HTML 页面返回给客户端。
- 支持通过
-
参数绑定与校验:
- 提供强大的数据绑定功能,使用
HandlerMethodArgumentResolver
自动解析请求参数、路径变量、请求体等,并注入到控制器方法参数。 - 集成参数校验功能,如支持
@Valid
和 Hibernate Validator。
- 提供强大的数据绑定功能,使用
-
返回数据格式化:
- 支持
@ResponseBody
和HttpMessageConverter
将控制器方法返回的对象自动序列化为 JSON 或 XML 格式。
- 支持
-
国际化支持:
- 提供
LocaleResolver
和国际化资源文件的支持,可根据客户端的语言设置动态返回多语言内容。
- 提供
-
拦截器机制:
- 提供
HandlerInterceptor
,可在请求处理前后、视图渲染前后执行额外逻辑,例如权限验证、日志记录和性能监控。
- 提供
-
模型管理:
- 提供
Model
和ModelAndView
,方便在控制器中设置数据并传递到视图层。
- 提供
-
表单处理:
- 支持通过
@ModelAttribute
或@RequestParam
注解,将表单数据绑定到对象,简化表单提交处理。
- 支持通过
-
异常处理:
- 支持
@ExceptionHandler
和全局异常处理机制,通过ControllerAdvice
处理应用中的异常并返回友好的错误信息。
- 支持
-
文件上传:
- 提供对
multipart/form-data
请求的支持,使用MultipartResolver
和@RequestPart
处理文件上传。
- 提供对
-
静态资源处理:
- 提供对静态资源(如 CSS、JS、图片等)的高效处理与缓存管理,支持通过
ResourceHandler
配置静态资源路径。
- 提供对静态资源(如 CSS、JS、图片等)的高效处理与缓存管理,支持通过
-
类型转换器:
- 提供
Converter
和Formatter
接口,用于在请求参数和控制器方法参数之间进行类型转换。 - 支持简单数据类型(如
String
转换为Integer
)和复杂对象的转换(如自定义的日期格式解析)。
- 提供
-
灵活的扩展机制:
- 提供接口如
HandlerAdapter
、HandlerMethodArgumentResolver
、ViewResolver
等,允许开发者灵活扩展框架功能。
- 提供接口如
1. DispatcherServlet(前端控制器)
- 执行顺序:第 1 步(请求的入口)。
- 作用:
- 是 Spring MVC 的核心调度器,负责接收所有客户端请求。
- 将请求分发给其他组件(如
HandlerMapping
、HandlerAdapter
),最终生成响应。
- 职责:
- 协调请求和响应。
- 统一管理所有请求的分发,解耦各个组件。
- 代码注册 DispatcherServlet:
@Configuration public class WebConfig { @Bean public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(DispatcherServlet dispatcherServlet) { ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(dispatcherServlet, "/"); registration.setName("dispatcherServlet"); registration.setLoadOnStartup(1); return registration; } @Bean public DispatcherServlet dispatcherServlet() { return new DispatcherServlet(); } }
2. HandlerMapping(处理器映射器)
- 执行顺序:第 2 步(查找处理器)。
- 作用:
- 根据请求 URL 和 HTTP 方法(如 GET/POST)找到对应的控制器方法(Controller)。
- 存储 URL 和控制器方法的映射关系。
- 常用实现:
RequestMappingHandlerMapping
:通过@RequestMapping
注解映射 URL。SimpleUrlHandlerMapping
:通过 XML 配置 URL 和处理器映射。
- 使用示例:
请求:@Controller public class MyController { @RequestMapping("/hello") public String hello() { return "hello"; } }
GET /hello
- HandlerMapping 查找并匹配
hello()
方法。
- HandlerMapping 查找并匹配
3. HandlerAdapter(处理器适配器)
- 执行顺序:第 3 步(调用处理器)。
- 作用:
- 负责调用具体的处理器方法(控制器方法)。
- 解耦
DispatcherServlet
和具体的处理器。 - 支持多种类型的处理器。
- 常用实现:
RequestMappingHandlerAdapter
:适配基于@RequestMapping
的控制器方法。HttpRequestHandlerAdapter
:适配实现HttpRequestHandler
接口的类。
- 使用示例:
请求:@RequestMapping("/user/{id}") public String getUser(@PathVariable("id") int id) { return "User ID: " + id; }
GET /user/42
- HandlerAdapter 调用
getUser()
方法并注入id=42
。
- HandlerAdapter 调用
4. HandlerInterceptor(拦截器)
-
执行顺序:贯穿整个请求流程:
preHandle
:控制器方法执行之前。postHandle
:控制器方法执行之后,视图渲染之前。afterCompletion
:整个请求完成之后(包括视图渲染)。
-
作用:
- 用于日志记录、权限验证、性能监控、资源清理等。
-
使用示例:
public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("控制器方法执行之前"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("控制器方法执行之后"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("视图渲染之后"); } }
注册拦截器:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); } }
5. Controller(控制器)
- 执行顺序:第 4 步(执行业务逻辑)。
- 作用:
- 处理用户请求,执行业务逻辑,调用服务层,并返回结果。
- 可以返回视图名称、
ModelAndView
对象,或直接返回 JSON 数据。
- 使用示例:
请求:@Controller public class MyController { @RequestMapping("/greet") public String greet(@RequestParam("name") String name, Model model) { model.addAttribute("message", "Hello, " + name + "!"); return "greeting"; // 返回视图名称 } }
GET /greet?name=Alice
6. HandlerMethodArgumentResolver(参数解析器)
- 执行顺序:控制器方法参数解析时。
- 作用:
- 解析请求参数,并将其注入到控制器方法参数中。
- 常用解析器:
RequestParamMethodArgumentResolver
:解析@RequestParam
。PathVariableMethodArgumentResolver
:解析@PathVariable
。RequestBodyMethodArgumentResolver
:解析@RequestBody
。
- 使用示例:
请求:@RequestMapping("/user") public String getUser(@RequestParam("id") int id, @RequestHeader("User-Agent") String userAgent) { return "User ID: " + id + ", User-Agent: " + userAgent; }
GET /user?id=42
,User-Agent: Mozilla/5.0
-
定义自定义注解:
创建一个注解来标记需要解析的参数。@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface MyCustomAnnotation { }
-
实现参数解析器:
实现HandlerMethodArgumentResolver
接口,自定义参数解析逻辑。public class MyCustomArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { // 判断是否支持当前参数 return parameter.getParameterAnnotation(MyCustomAnnotation.class) != null; } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 从请求中提取参数并解析为目标对象 String customParam = webRequest.getParameter("customParam"); return new CustomObject(customParam); } }
-
注册解析器:
使用WebMvcConfigurer
接口将解析器注册到 Spring 上下文中。@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new MyCustomArgumentResolver()); } }
-
在控制器中使用:
在控制器方法中,使用自定义注解标记需要解析的参数,Spring MVC 会自动应用解析器。@RestController public class MyController { @GetMapping("/process") public String processRequest(@MyCustomAnnotation CustomObject customObject) { return "Processed: " + customObject.getValue(); } }
-
发送 HTTP 请求:
发送符合解析器要求的请求,例如:GET /process?customParam=Hello
6 验证解析效果:
确保请求被正确解析并传递到控制器方法中。
返回结果示例:
Processed: Hello
7. 类型转换器(Converter 和 Formatter)
-
执行顺序:在参数绑定或返回值处理中。
-
作用:
- 将请求中的字符串数据转换为方法参数所需的目标类型(如
String -> Integer
、String -> Date
)。 - 也可以将对象转换为字符串进行返回(如
Date -> String
)。
- 将请求中的字符串数据转换为方法参数所需的目标类型(如
-
常用实现:
Converter
:用于简单的类型转换。Formatter
:扩展Converter
,支持复杂格式化(如日期格式)。
-
使用示例:
自定义
Converter
示例:public class StringToUserConverter implements Converter<String, User> { @Override public User convert(String source) { String[] data = source.split(","); User user = new User(); user.setId(Integer.parseInt(data[0])); user.setName(data[1]); return user; } }
注册类型转换器:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new StringToUserConverter()); } }
使用类型转换器:
@RequestMapping("/convertUser") public String convertUser(@RequestParam("user") User user) { return "User ID: " + user.getId() + ", Name: " + user.getName(); }
请求:
GET /convertUser?user=1,Alice
自定义
Formatter
示例(日期格式化):public class DateFormatter implements Formatter<Date> { private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); @Override public Date parse(String text, Locale locale) throws ParseException { return dateFormat.parse(text); } @Override public String print(Date object, Locale locale) { return dateFormat.format(object); } }
注册日期格式化器:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addFormatter(new DateFormatter()); } }
使用日期格式化器:
@RequestMapping("/convertDate") public String convertDate(@RequestParam("date") Date date) { return "Converted Date: " + date.toString(); }
请求:
GET /convertDate?date=2025-01-13
8. ModelAndView
- 执行顺序:控制器方法执行完毕后返回。
- 作用:
- 封装控制器返回的结果,包括:
- 模型数据(Model):供视图渲染的数据。
- 视图名称(View Name):指定要渲染的视图。
- 封装控制器返回的结果,包括:
- 使用示例:
@RequestMapping("/welcome") public ModelAndView welcome() { ModelAndView mav = new ModelAndView("welcome"); mav.addObject("message", "Welcome to Spring MVC!"); return mav; }
9. ViewResolver(视图解析器)
- 执行顺序:在
ModelAndView
返回后。 - 作用:
- 将逻辑视图名称解析为实际的物理视图路径。
- 常用实现:
InternalResourceViewResolver
:解析 JSP 文件。ThymeleafViewResolver
:解析 Thymeleaf 模板。
- 配置示例:
@Configuration public class WebConfig implements WebMvcConfigurer { @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); return resolver; } }
10. View(视图)
- 执行顺序:视图解析完成后。
- 作用:
- 渲染视图,将模型数据填充到视图中,生成最终的 HTML 响应。
- 使用示例(JSP 渲染):
<!-- /WEB-INF/views/welcome.jsp --> <html> <body> <h1>${message}</h1> <!-- 输出:Welcome to Spring MVC! --> </body> </html>
11. ResponseBody(直接返回 JSON 数据)
- 执行顺序:当方法标注
@ResponseBody
时,跳过视图解析,直接返回数据。 - 作用:
- 将控制器方法返回值(如对象、集合)直接序列化为 JSON 或 XML 格式,写入响应体。
- 使用示例:
请求:@RequestMapping("/user") @ResponseBody public User getUser() { return new User(42, "Alice"); }
GET /user
响应:{ "id": 42, "name": "Alice" }
完整流程总结
- DispatcherServlet:接收请求,分发给后续组件。
- HandlerMapping:根据 URL 查找对应的控制器方法。
- HandlerAdapter:适配并调用控制器方法。
- HandlerInterceptor:在请求的前后执行拦截逻辑。
- Controller:处理请求,返回结果。
- HandlerMethodArgumentResolver:解析控制器方法参数。
- ModelAndView:封装模型数据和视图名称。
- ViewResolver:解析逻辑视图名称为物理路径。
- View:渲染视图,生成响应内容。
- ResponseBody:直接返回 JSON 数据。