文章目录
- 一、请求处理整体流程
-
- [1.1 SpringMVC请求处理流程](#1.1 SpringMVC请求处理流程)
- [1.2 核心组件职责](#1.2 核心组件职责)
- [二、DispatcherServlet 核心架构](#二、DispatcherServlet 核心架构)
-
- [2.1 DispatcherServlet 继承体系](#2.1 DispatcherServlet 继承体系)
- [2.2 核心成员变量](#2.2 核心成员变量)
- [2.3 请求分发核心方法](#2.3 请求分发核心方法)
- [2.4 初始化流程源码](#2.4 初始化流程源码)
- 三、处理器映射(HandlerMapping)
-
- [3.1 HandlerMapping 接口定义](#3.1 HandlerMapping 接口定义)
- [3.2 RequestMappingHandlerMapping 源码解析](#3.2 RequestMappingHandlerMapping 源码解析)
- [3.3 匹配流程图](#3.3 匹配流程图)
- 四、处理器适配器(HandlerAdapter)
-
- [4.1 HandlerAdapter 接口](#4.1 HandlerAdapter 接口)
- [4.2 RequestMappingHandlerAdapter 源码](#4.2 RequestMappingHandlerAdapter 源码)
- [4.3 参数解析器体系](#4.3 参数解析器体系)
- 五、参数绑定与数据转换
-
- [5.1 WebDataBinder 机制](#5.1 WebDataBinder 机制)
- [5.2 类型转换流程](#5.2 类型转换流程)
- [5.3 自定义 Converter 示例](#5.3 自定义 Converter 示例)
- [六、 视图解析器(ViewResolver)](#六、 视图解析器(ViewResolver))
-
- [6.1 ViewResolver 接口](#6.1 ViewResolver 接口)
- [6.2 常见 ViewResolver 实现](#6.2 常见 ViewResolver 实现)
- [6.3 InternalResourceViewResolver 源码](#6.3 InternalResourceViewResolver 源码)
- [6.4 视图渲染流程](#6.4 视图渲染流程)
- 七、异常处理机制
-
- [7.1 异常处理体系](#7.1 异常处理体系)
- [7.2 @ExceptionHandler 处理流程](#7.2 @ExceptionHandler 处理流程)
- 八、请求处理完整时序图
- 九、总结与最佳实践
-
- [9.1 核心组件](#9.1 核心组件)
- [9.2 开发最佳实践](#9.2 开发最佳实践)
一、请求处理整体流程
1.1 SpringMVC请求处理流程
复制代码
+-----------------------------------------------------------------------+
| SpringMVC 请求处理流程 |
+-----------------------------------------------------------------------+
| |
| +---------+ +-------------+ +-------------+ +-------------+ |
| | HTTP |---->| Dispatcher |---->| Handler |---->| Handler | |
| | Request| | Servlet | | Mapping | | Adapter | |
| +---------+ +-------------+ +-------------+ +-------------+ |
| | | | |
| | | v |
| | | +-------------+ |
| | | | Controller | |
| | | | Method | |
| | | +-------------+ |
| | | | |
| +---------------------+-----------------+----------------+ |
| | | | v |
| | +------+------+ +------+------+ +------+------+ |
| | |ViewResolver | | View Object | | ModelAnd | |
| | | & View | | Rendering | | View | |
| | +-------------+ +-------------+ +-------------+ |
| | | |
| v v |
| +-------------+ +-------------+ |
| |HTTP Response|<--------------------------------------| Rendered | |
| +-------------+ | View | |
| +-------------+ |
+-----------------------------------------------------------------------+
1.2 核心组件职责
| 组件 |
类型 |
职责 |
| DispatcherServlet |
Servlet |
请求分发的核心枢纽 |
| HandlerMapping |
接口 |
根据URL映射到处理器 |
| HandlerAdapter |
接口 |
适配并执行处理器 |
| Controller |
接口 |
业务逻辑处理 |
| ViewResolver |
接口 |
解析视图名称到具体视图 |
| View |
接口 |
渲染视图内容 |
| HandlerExceptionResolver |
接口 |
处理请求处理中的异常 |
二、DispatcherServlet 核心架构
2.1 DispatcherServlet 继承体系
java
复制代码
// DispatcherServlet 继承层次
// 文件:org.springframework.web.servlet.DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
// 1. 继承自 HttpServletBean(HttpServlet 的 Spring 增强版本)
// 2. FrameworkServlet 实现了 doGet/doPost 等 HTTP 方法
// 3. DispatcherServlet 实现具体的请求分发逻辑
}
// 继承链:
// HttpServlet (Java SE)
// ↑
// HttpServletBean (Spring Web)
// ↑
// FrameworkServlet (Spring Web)
// ↑
2.2 核心成员变量
java
复制代码
// DispatcherServlet.java 核心成员
// 文件:org.springframework.web.servlet.DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
// 1. 处理器映射器列表(按优先级)
private List<HandlerMapping> handlerMappings;
// 2. 处理器适配器列表(按优先级)
private List<HandlerAdapter> handlerAdapters;
// 3. 视图解析器列表
private List<ViewResolver> viewResolvers;
// 4. 异常解析器列表
private List<HandlerExceptionResolver> handlerExceptionResolvers;
// 5. Multipart 解析器(文件上传)
private MultipartResolver multipartResolver;
// 6. 本地化解析器
private LocaleResolver localeResolver;
// 7. 主题解析器
private ThemeResolver themeResolver;
// 8. FlashMap 管理器
private FlashMapManager flashMapManager;
}
2.3 请求分发核心方法
java
复制代码
// DispatcherServlet#doDispatch - 请求分发的核心入口
// 文件:org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request,
HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain handlerExecutionChain = null;
ModelAndView mv = null;
Exception dispatchException = null;
try {
// ============ 步骤1: 检查是否为文件上传请求 ============
processedRequest = checkMultipart(request);
multipartRequestResolver.parseRequest(request);
// ============ 步骤2: 根据URL获取处理器 ============
// 核心:从 handlerMappings 中查找匹配的处理器
handlerExecutionChain = getHandler(processedRequest);
if (handlerExecutionChain == null) {
// 无处理器映射,返回404
noHandlerFound(processedRequest, response);
return;
}
// ============ 步骤3: 获取处理器适配器 ============
HandlerAdapter ha = getHandlerAdapter(handlerExecutionChain.getHandler());
// ============ 步骤4: 执行处理器(调用Controller方法) ============
mv = ha.handle(processedRequest, response, handlerExecutionChain.getHandler());
// ============ 步骤5: 处理异步结果(如有) ============
applyDefaultViewName(processedRequest, mv);
// ============ 步骤6: 渲染视图 ============
render(mv, processedRequest, response);
} catch (Exception e) {
dispatchException = e;
} catch (Throwable e) {
dispatchException = new NestedServletException("Handler dispatch failed", e);
}
// ============ 步骤7: 处理异常 ============
processDispatchResult(processedRequest, response, handlerExecutionChain,
mv, dispatchException);
}
// 源码位置总结:
// 1. getHandler() -> 遍历 HandlerMapping 查找处理器
// 2. getHandlerAdapter() -> 遍历 HandlerAdapter 匹配适配器
// 3. ha.handle() -> 执行 Controller 方法
// 4. render() -> 渲染视图并输出
2.4 初始化流程源码
java
复制代码
// DispatcherServlet#initStrategies - 初始化策略组件
// 文件:org.springframework.web.servlet.DispatcherServlet
@Override
protected void initStrategies(ApplicationContext context) {
// 1. 初始化 Multipart 解析器(文件上传)
initMultipartResolver(context);
// 2. 初始化本地化解析器
initLocaleResolver(context);
// 3. 初始化主题解析器
initThemeResolver(context);
// 4. 初始化处理器映射器
initHandlerMappings(context);
// 5. 初始化处理器适配器
initHandlerAdapters(context);
// 6. 初始化异常解析器
initHandlerExceptionResolvers(context);
// 7. 初始化视图解析器
initViewResolvers(context);
// 8. 初始化 FlashMap 管理器
initFlashMapSupport(context);
}
// 以 HandlerMapping 为例的初始化逻辑
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 从 Spring 容器中获取所有 HandlerMapping 类型的 Bean
if (detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
// 按优先级排序
if (logger.isDebugEnabled()) {
logger.debug("Found " + matchingBeans.size() + " HandlerMapping beans");
}
this.handlerMappings = new ArrayList<>(matchingBeans.values());
OrderComparator.sort(this.handlerMappings);
} else {
// 只获取名为 "handlerMapping" 的 Bean
this.handlerMappings =Collections.singletonList(
context.getBean("handlerMapping", HandlerMapping.class));
}
// 确保至少有一个 HandlerMapping
if (this.handlerMappings.isEmpty()) {
// 使用默认的 SimpleUrlHandlerMapping
this.handlerMappings.add(this.detectAllHandlerMappings ?
new EmptyHandlerMapping(context) : null);
}
}
三、处理器映射(HandlerMapping)
3.1 HandlerMapping 接口定义
java
复制代码
// HandlerMapping 接口
// 文件:org.springframework.web.servlet.HandlerMapping
public interface HandlerMapping {
// 静态常量:辅助对象属性键
String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";
String PATH_WITHIN_HANDLER_MAPPING_ATTR = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
String BEST_MATCHING_PATTERN_ATTR = HandlerMapping.class.getName() + ".bestMatchingPattern";
String INTROSPECT_TYPE_LEVEL_MAPPING_ATTR = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
String URI_TEMPLATE_VARIABLES_ATTR = HandlerMapping.class.getName() + ".uriTemplateVariables";
// 获取处理器执行链
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
// 处理器执行链:包含处理器和所有拦截器
public class HandlerExecutionChain {
private final Object handler; // 实际处理器(Controller)
private final List<HandlerInterceptor> interceptors; // 拦截器链
public HandlerExecutionChain(Object handler) {
this(handler, (List<HandlerInterceptor>) null);
}
public HandlerExecutionChain(Object handler,
List<HandlerInterceptor> interceptors) {
// Handler 可能是 HandlerMethod(带 @RequestMapping 的方法)
// 或者是具体的 Handler(实现了 HttpRequestHandler 的 Bean)
}
}
3.2 RequestMappingHandlerMapping 源码解析
java
复制代码
// RequestMappingHandlerMapping - 处理 @RequestMapping 注解的映射
// 文件:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
// 1. 检测带 @RequestMapping 的方法
@Override
protected boolean isHandler(Class<?> beanType) {
// 检查类上是否有 @Controller 或 @RequestMapping 注解
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
// 2. 获取方法级别的映射信息
@Override
protected RequestMappingInfo getMappingForMethod(Method method,
Class<?> handlerType) {
RequestMappingInfo info = null;
// 优先处理方法上的 @RequestMapping
RequestMapping methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(
method, RequestMapping.class);
if (methodAnnotation != null) {
// 构建方法级别的 RequestMappingInfo
RequestMappingInfo.BuilderConfiguration config =
new RequestMappingInfo.BuilderConfiguration();
config.setPatternTemplate(this.patternParser);
info = RequestMappingInfo
.paths(resolvePatterns(methodAnnotation))
.methods(methodAnnotation.method())
.params(methodAnnotation.params())
.headers(methodAnnotation.headers())
.consumes(methodAnnotation.consumes())
.produces(methodAnnotation.produces())
.mappingName(getMappingName(method, methodAnnotation))
.options(config)
.build();
}
// 合并类级别的映射信息
RequestMapping classAnnotation = AnnotatedElementUtils.findMergedAnnotation(
handlerType, RequestMapping.class);
if (classAnnotation != null) {
info = RequestMappingInfo
.paths(resolvePatterns(classAnnotation))
.methods(classAnnotation.method())
.params(classAnnotation.params())
.headers(classAnnotation.headers())
.consumes(classAnnotation.consumes())
.produces(classAnnotation.produces())
.mappingName(getMappingName(handlerType, classAnnotation))
.options(infoBuilderConfig)
.build()
.combine(info); // 组合类和方法级别的映射
}
return info;
}
// 3. 注册处理器方法
@Override
protected void registerHandlerMethod(Object handler,
Method method,
RequestMappingInfo mapping) {
// 最终注册到父类的 Map 中
super.registerHandlerMethod(handler, method, mapping);
}
}
3.3 匹配流程图
复制代码
┌────────────────────────────────────────────────────────────────┐
│ HandlerMapping 匹配流程 │
├────────────────────────────────────────────────────────────────┤
│ │
│ 步骤1: 根据请求获取 URL │
│ ├─ GET /api/users/123 │
│ └─ /api/users/{id} │
│ │
│ ▼ │
│ 步骤2: 模式匹配(Ant风格或PathPattern) │
│ ├─ /api/users/* -> /api/users/123 ✓ │
│ ├─ /api/users/** -> /api/users/abc/def ✓ │
│ └─ /api/users/{id} -> 捕获变量 id=123 │
│ │
│ ▼ │
│ 步骤3: HTTP 方法匹配 │
│ ├─ @GetMapping │
│ ├─ @PostMapping │
│ └─ 请求方法 GET → @GetMapping ✓ │
│ │
│ ▼ │
│ 步骤4: 参数/-header 匹配 │
│ ├─ @RequestMapping(params="action=create") │
│ └─ ?action=create → 匹配 ✓ │
│ │
│ ▼ │
│ 步骤5: Content-Type/Accept 匹配 │
│ ├─ consumes = "application/json" │
│ └─ 请求 Content-Type = application/json ✓ │
│ │
│ ▼ │
│ 步骤6: 最佳匹配选择 │
│ └─ 选择最具体的映射(path variable > ANT pattern) │
│ │
└────────────────────────────────────────────────────────────────┘
四、处理器适配器(HandlerAdapter)
4.1 HandlerAdapter 接口
java
复制代码
// HandlerAdapter 接口
// 文件:org.springframework.web.servlet.HandlerAdapter
public interface HandlerAdapter {
// 判断是否支持此处理器
boolean supports(Object handler);
// 执行处理器并返回 ModelAndView
ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception;
// 获取最后修改时间(用于缓存优化)
long getLastModified(HttpServletRequest request, Object handler);
}
// 主要实现类:
// 1. RequestMappingHandlerAdapter - 处理带 @RequestMapping 的方法
// 2. HttpRequestHandlerAdapter - 处理实现 HttpRequestHandler 的 Bean
// 3. SimpleControllerHandlerAdapter - 处理实现 Controller 接口的 Bean
4.2 RequestMappingHandlerAdapter 源码
java
复制代码
// RequestMappingHandlerAdapter - 核心适配器实现
// 文件:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
// 1. 支持判断:只要 handler 是 HandlerMethod 类型
@Override
public boolean supports(Object handler) {
return handler instanceof HandlerMethod;
}
// 2. 核心处理方法
@Override
public ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取或创建该请求的 WebDataBinder 工厂
ServletInvocableHandlerMethod invocableMethod =
getDataBinderFactory(handlerMethod)
.createInvocableHandlerMethod(handlerMethod);
// 设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(
this.argumentResolvers);
// 设置返回值处理器
invocableMethod.setHandlerMethodReturnValueHandlers(
this.returnValueHandlers);
// 执行方法并处理返回值
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
invocableMethod.invokeAndHandle(request, response, mavContainer);
// 返回结果
return getModelAndView(mavContainer, handlerMethod, request, response);
}
// 3. 方法调用核心逻辑
public void invokeAndHandle(ServletRequest request,
ServletResponse response,
ModelAndViewContainer mavContainer) throws Exception {
// ============ 步骤1: 解析并绑定参数 ============
Object returnValue = null;
try {
// 解析方法参数并调用
returnValue = invokeForRequest(request, response, mavContainer);
// ============ 步骤2: 处理返回值 ============
handleReturnValue(returnValue,
returnType,
mavContainer);
} catch (Exception ex) {
// 处理异常
throw ex;
}
}
}
4.3 参数解析器体系
java
复制代码
// 参数解析器接口
// 文件:org.springframework.web.method.support.HandlerMethodArgumentResolver
public interface HandlerMethodArgumentResolver {
// 判断是否支持该参数
boolean supportsParameter(MethodParameter parameter);
// 解析参数值
Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
WebRequest request) throws Exception;
}
// 常用参数解析器:
// 1. RequestParamMethodArgumentResolver - 处理 @RequestParam
// 2. RequestParamMapMethodArgumentResolver - 处理 @RequestParam Map
// 3. PathVariableMethodArgumentResolver - 处理 @PathVariable
// 4. RequestHeaderMethodArgumentResolver - 处理 @RequestHeader
// 5. CookieValueMethodArgumentResolver - 处理 @CookieValue
// 6. RequestBodyMethodArgumentResolver - 处理 @RequestBody
// 7. ModelAttributeMethodArgumentResolver - 处理 @ModelAttribute
// 8. PrincipalMethodArgumentResolver - 处理 Principal
// 示例:PathVariable 解析器
public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 检查参数是否有 @PathVariable 注解
return parameter.hasParameterAnnotation(PathVariable.class);
}
@Override
protected Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
WebRequest request) throws Exception {
// 获取 @PathVariable 注解信息
PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
String variableName = ann.value();
// 从 URI 模板变量中获取值
Map<String, String> uriVars = getUriTemplateVariables(request);
String value = uriVars.get(variableName);
if (value == null) {
// 如果是必需的但没有值,抛出异常
if (ann.required()) {
throw new MissingPathVariableException(
"Missing path variable '" + variableName + "'");
}
return null;
}
// 类型转换(如 String -> Long)
return conversionService.convert(value, parameter.getParameterType());
}
}
五、参数绑定与数据转换
5.1 WebDataBinder 机制
java
复制代码
// WebDataBinder - Spring 的数据绑定核心
// 文件:org.springframework.web.bind.WebDataBinder
public class WebDataBinder {
// 绑定的目标对象
private Object target;
// 目标对象的 Class
private Class<?> targetType;
// 绑定结果
private BindingResult bindingResult;
// 类型转换器
private ConversionService conversionService;
// 属性编辑器(已废弃,推荐使用 Converter)
private Map<Class<?>, PropertyEditor> customEditors;
// 校验器
private Validator validator;
// 核心绑定方法
public void bind(WebRequest request) {
// 获取请求参数名值对
Map<String, String[]> parameters = request.getParameterMap();
// 创建 MutablePropertyValues
MutablePropertyValues mpvs = new MutablePropertyValues();
for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
String name = entry.getKey();
String[] values = entry.getValue();
// 处理数组类型参数
if (values.length == 1) {
mpvs.addPropertyValue(name, values[0]);
} else {
mpvs.addPropertyValue(name, values);
}
}
// 执行绑定
doBind(mpvs);
}
// 执行实际的绑定逻辑
protected void doBind(MutablePropertyValues mpvs) {
// 检查是否忽略未知属性
checkAllowedFields(mpvs);
// 检查是否忽略必填字段
checkRequiredFields(mpvs);
// 应用属性编辑器或转换器
applyPropertyValues(mpvs);
}
}
5.2 类型转换流程
复制代码
┌────────────────────────────────────────────────────────────────┐
│ Spring 类型转换流程 │
├────────────────────────────────────────────────────────────────┤
│ │
│ 请求参数(String) │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 阶段1: 原始值解析 │ │
│ │ - request.getParameter("username") │ │
│ │ - @PathVariable 从 URL 中提取 │ │
│ │ - @RequestBody 从请求体中 JSON 解析 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 阶段2: 类型转换 │ │
│ │ - 使用 ConversionService │ │
│ │ - String → Integer/Long/Date/LocalDate │ │
│ │ - 支持自定义 Converter<S, T> │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 阶段3: 数据校验(可选) │ │
│ │ - 使用 JSR-303 注解 (@Valid, @NotNull, @Size...) │ │
│ │ - 将校验结果放入 BindingResult │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 绑定后的目标对象 │
│ │
└────────────────────────────────────────────────────────────────┘
5.3 自定义 Converter 示例
java
复制代码
// 配置自定义类型转换器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// 添加自定义转换器:String -> UserId
registry.addConverter(new Converter<String, UserId>() {
@Override
public UserId convert(String source) {
if (source == null || source.isEmpty()) {
return null;
}
return new UserId(Long.parseLong(source));
}
});
// 添加自定义转换器:String -> LocalDate
registry.addConverter(new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String source) {
if (source == null || source.isEmpty()) {
return null;
}
return LocalDate.parse(source, DateTimeFormatter.ISO_DATE);
}
});
}
}
六、 视图解析器(ViewResolver)
6.1 ViewResolver 接口
java
复制代码
// ViewResolver 接口
// 文件:org.springframework.web.servlet.ViewResolver
public interface ViewResolver {
// 根据视图名称解析视图
View resolveViewName(String viewName, Locale locale) throws Exception;
}
// View 接口
public interface View {
// 渲染视图
void render(Map<String, ?> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception;
// 获取内容类型
String getContentType();
}
6.2 常见 ViewResolver 实现
| ViewResolver |
用途 |
配置前缀 |
| InternalResourceViewResolver |
JSP/HTML |
prefix/suffix |
| BeanNameViewResolver |
按 Bean 名称查找 |
- |
| ContentNegotiatingViewResolver |
内容协商 |
- |
| FreeMarkerViewResolver |
FreeMarker 模板 |
- |
| ThymeleafViewResolver |
Thymeleaf 模板 |
- |
| MappingJackson2JsonView |
JSON 视图 |
json/ |
6.3 InternalResourceViewResolver 源码
java
复制代码
// InternalResourceViewResolver 源码
// 文件:org.springframework.web.servlet.view.InternalResourceViewResolver
public class InternalResourceViewResolver extends UrlBasedViewResolver {
private String prefix; // 视图前缀,如 /WEB-INF/views/
private String suffix; // 视图后缀,如 .jsp
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
// 构造完整路径
InternalResourceView view = (InternalResourceView) super.buildView(viewName);
// 设置前缀和后缀
if (this.prefix != null) {
view.setUrl(this.prefix + viewName + this.suffix);
}
// 设置属性
view.setAlwaysInclude(this.alwaysInclude);
return view;
}
}
// 配置示例
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
// 配置 JSP 视图解析器
registry.jsp("/WEB-INF/views/", ".jsp");
// 配置 Thymeleaf
registry.freemarker();
}
}
6.4 视图渲染流程
java
复制代码
// DispatcherServlet#render 方法
// 文件:org.springframework.web.servlet.DispatcherServlet
protected void render(ModelAndView mv,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
// 1. 确定视图名称
String viewName = mv.getViewName();
if (viewName == null) {
// 如果没有视图名称,根据 HTTP 状态码确定
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// 2. 遍历 ViewResolver 解析视图
View view = null;
for (ViewResolver resolver : this.viewResolvers) {
view = resolver.resolveViewName(viewName, locale);
if (view != null) {
break;
}
}
if (view == null) {
throw new ServletException("Could not resolve view with name '" + viewName + "'");
}
// 3. 设置响应内容类型
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 4. 渲染视图
view.render(mv.getModelInternal(), request, response);
}
// InternalResourceView 渲染
public class InternalResourceView extends AbstractUrlBasedView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
// 1. 将模型数据暴露到请求属性
exposeModelAsRequestAttributes(model, request);
// 2. 转发到 JSP
RequestDispatcher rd = getRequestDispatcher(request, getUrl());
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher");
}
// 3. 如果需要 include,则 include,否则 forward
if (useInclude(request, response)) {
response.setContentType(getContentType());
rd.include(request, response);
} else {
rd.forward(request, response);
}
}
}
七、异常处理机制
7.1 异常处理体系
java
复制代码
// HandlerExceptionResolver 接口
// 文件:org.springframework.web.servlet.HandlerExceptionResolver
public interface HandlerExceptionResolver {
// 解析异常,返回 ModelAndView
ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex);
}
// 主要实现:
// 1. ExceptionHandlerExceptionResolver - 处理 @ExceptionHandler
// 2. ResponseStatusExceptionResolver - 处理 @ResponseStatus
// 3. DefaultHandlerExceptionResolver - 处理 Spring 标准异常
7.2 @ExceptionHandler 处理流程
java
复制代码
// ExceptionHandlerExceptionResolver 核心逻辑
// 文件:org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
public class ExceptionHandlerExceptionResolver
extends AbstractHandlerMethodExceptionResolver
implements InitializingBean {
// 1. 查找异常处理方法
@Override
protected HandlerMethod getExceptionHandlerMethod(
Exception ex, Method handlerMethod) {
// 获取异常类型
Class<?> exceptionType = ex.getClass();
// 在缓存中查找
Map<ExceptionMappingDescriptor, HandlerMethod> handlers = this.exceptionHandlerCache;
// 遍历异常类型层次,从最具体的异常开始匹配
while (exceptionType != null) {
// 查找直接匹配的异常处理方法
for (Map.Entry<ExceptionMappingDescriptor, HandlerMethod> entry :
handlers.entrySet()) {
ExceptionMappingDescriptor descriptor = entry.getKey();
// 检查异常类型是否匹配
if (descriptor.getExceptionType().isAssignableFrom(exceptionType)) {
return entry.getValue();
}
}
// 继续查找父类
exceptionType = exceptionType.getSuperclass();
}
return null;
}
// 2. 执行异常处理方法
public ModelAndView resolveException(Exception ex, HandlerMethod handlerMethod) {
return doResolveException(request, response, handlerMethod, ex);
}
}
// 使用示例
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public ModelAndView handleBusinessException(BusinessException ex) {
ModelAndView mav = new ModelAndView("error/business");
mav.addObject("errorMsg", ex.getMessage());
mav.addObject("errorCode", ex.getCode());
return mav;
}
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public Result<Void> handleValidationException(MethodArgumentNotValidException ex) {
String msg = ex.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return Result.fail(msg);
}
// 处理未知异常
@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception ex) {
log.error("System error", ex);
ModelAndView mav = new ModelAndView("error/500");
return mav;
}
}
八、请求处理完整时序图
复制代码
┌────────────────────────────────────────────────────────────────────────────┐
│ 请求处理完整时序图 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client DispatcherServlet HandlerMapping HandlerAdapter │
│ │ │ │ │ │
│ ├─HTTP Request───►│ │ │ │
│ │ │ │ │ │
│ │ ├─ getHandler() ────►│ │ │
│ │ │ │ │ │
│ │ │◄─HandlerMethod────┤ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ ├─ getHandlerAdapter() ─────────────►│ │
│ │ │ │ │ │
│ │ │◄─────────HandlerAdapter─────────────┤ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ ┌──────┴──────┐ │
│ │ │ │ │ 参数绑定 │ │
│ │ │ │ │ @RequestParam│ │
│ │ │ │ │ @PathVariable│ │
│ │ │ │ │ @RequestBody│ │
│ │ │ │ └──────┬──────┘ │
│ │ │ │ │ │
│ │ │ │ ┌──────┴──────┐ │
│ │ │ │ │ 调用 Controller│ │
│ │ │ │ └──────┬──────┘ │
│ │ │ │ │ │
│ │ │ │ ┌──────┴──────┐ │
│ │ │ │ │ 返回值处理 │ │
│ │ │ │ │ @ResponseBody│ │
│ │ │ │ │ ViewName │ │
│ │ │ │ │ ModelAndView│ │
│ │ │ │ └──────┬──────┘ │
│ │ │ │ │ │
│ │◄───Response──────┤ │ │ │
│ │ │ │ │ │
│ │ ├─ render() ────────────────────────────►│ ViewResolver│
│ │ │ │ │ │
│ │ │◄─────────────────────────────────────────┘ │
│ │ │ │ │ │
│ │ │ │ │ │
└─────────────────────────────────────────────────────────────────────────────┘
九、总结与最佳实践
9.1 核心组件
| 阶段 |
关键组件 |
核心方法 |
| 请求接收 |
DispatcherServlet |
doDispatch() |
| 处理器查找 |
HandlerMapping |
getHandler() |
| 适配执行 |
HandlerAdapter |
handle() |
| 参数绑定 |
HandlerMethodArgumentResolver |
resolveArgument() |
| 业务处理 |
Controller |
@RequestMapping 方法 |
| 视图解析 |
ViewResolver |
resolveViewName() |
| 视图渲染 |
View |
render() |
| 异常处理 |
HandlerExceptionResolver |
resolveException() |
9.2 开发最佳实践
java
复制代码
// 1. Controller 规范写法
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
// 构造器注入(推荐)
public UserController(UserService userService) {
this.userService = userService;
}
// 2. 使用具体返回类型而非 Map
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
UserDTO user = userService.findById(id);
return ResponseEntity.ok(user);
}
// 3. 使用统一的响应包装
@PostMapping("/createUser")
public ResponseEntity<Result<Void>> createUser(@Valid @RequestBody CreateUserRequest request) {
userService.create(request);
return ResponseEntity.ok(Result.success());
}
}
// 4. 异常处理 @ControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public Result<Void> handleServiceException(ServiceException ex) {
return Result.fail(ex.getCode(), ex.getMessage());
}
}