0%

Spring MVC HandlerExceptionResolver 详解:异常处理的核心机制与实战

HandlerExceptionResolver 是 Spring MVC 中统一异常处理的核心接口,负责在视图渲染(render)前拦截 Controller 或 Handler 抛出的异常,通过解析异常生成 ModelAndView(用于视图渲染)或直接处理响应(如设置 HTTP 状态码、返回 JSON 错误信息),避免异常直接抛给用户,提升系统容错性和用户体验。从 “核心接口→实现类对比→ExceptionHandlerExceptionResolver 源码解析→实战场景” 四个维度,彻底讲透 HandlerExceptionResolver 的工作原理。

HandlerExceptionResolver 核心定义与设计目标

1. 核心接口方法

HandlerExceptionResolver 接口仅定义一个核心方法,所有实现类需通过该方法完成异常解析:

1
2
3
4
5
6
7
8
9
10
11
12
public interface HandlerExceptionResolver {
/**
* 解析异常,返回 ModelAndView 或直接处理响应
* @param request 当前 HTTP 请求
* @param response 当前 HTTP 响应
* @param handler 抛出异常的处理器(如 Controller 实例、HandlerMethod)
* @param ex 待处理的异常
* @return ModelAndView:包含错误视图和模型数据(需渲染);null:异常已直接处理(如设置响应码、返回 JSON)
*/
ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
关键逻辑:
  • 若返回 ModelAndView:DispatcherServlet 会继续渲染视图(如错误页面);
  • 若返回 null:表示异常已被 “直接处理”(如通过 response.sendError() 设置状态码,或通过 @ResponseBody 返回 JSON 错误信息);
  • 执行时机:在 Controller 方法执行后、视图渲染(render)前,属于 “异常处理的最后一道防线”。

2. 设计目标

  • 集中化异常处理:替代 try-catch 代码块,将分散在 Controller、Service 层的异常统一拦截处理;
  • 解耦异常处理与业务逻辑:业务代码无需关注异常处理细节,只需抛出异常,由 HandlerExceptionResolver 统一接管;
  • 灵活适配场景:支持不同异常处理策略(如视图渲染、JSON 响应、HTTP 状态码设置)。

HandlerExceptionResolver 四大核心实现类

Spring MVC 提供 4 个常用实现类,覆盖从 “标准异常映射” 到 “注解驱动” 的所有场景,以下是核心对比:

阅读全文 »

Spring MVC ViewResolver 详解:视图解析器的原理与实战

ViewResolver(视图解析器)是 Spring MVC 中连接 “逻辑视图名” 与 “物理视图” 的核心组件,其核心职责是 将 Controller 方法返回的逻辑视图名(如 "user/list")解析为具体的 View 对象(如 JSP、FreeMarker 模板),并触发视图渲染,最终将业务数据以页面形式呈现给用户。从 “核心原理→实现类解析→配置实战→渲染流程” 四个维度,彻底讲透 ViewResolver 的工作机制。

ViewResolver 核心定义与作用

ViewResolver 是一个接口,定义了视图解析的通用行为,所有视图解析器都需实现该接口,核心是 “逻辑视图名→View 对象” 的转换。

1. 核心接口方法

1
2
3
4
5
6
7
8
9
10
public interface ViewResolver {
/**
* 根据逻辑视图名和Locale,解析为具体的View对象
* @param viewName 逻辑视图名(如 Controller 返回的 "user/list")
* @param locale 语言区域(用于国际化视图,如中文/英文页面)
* @return View 对象(如 InternalResourceView 对应 JSP);null:无法解析该视图名
* @throws Exception 解析过程中发生异常(如视图文件不存在)
*/
View resolveViewName(String viewName, Locale locale) throws Exception;
}
  • 逻辑视图名:Controller 方法返回的字符串(如 return "user/list")或 ModelAndView 中的视图名,不包含物理路径和后缀;
  • View 对象:封装了视图的渲染逻辑(如 JSP 渲染、FreeMarker 模板填充),核心方法是 render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response),负责将 Model 数据填充到视图模板中。

2. 核心流程:从逻辑视图到页面渲染

ViewResolver 的工作流程可概括为 3 步:

  1. 接收逻辑视图名:DispatcherServlet 从 ModelAndView 中获取逻辑视图名(如 "user/list");
  2. 解析为物理视图路径:ViewResolver 根据配置的 “前缀 + 逻辑视图名 + 后缀” 生成物理路径(如 /WEB-INF/jsp/user/list.jsp);
  3. 创建 View 对象并渲染:根据物理路径创建对应的 View 对象(如 JstlView),调用其 render() 方法,将 Model 数据填充到视图模板,生成 HTML 响应。

ViewResolver 主要实现类解析

Spring MVC 提供了多个 ViewResolver 实现,支持不同类型的视图技术(如 JSP、FreeMarker、PDF),以下是核心实现类的对比与使用场景:

阅读全文 »

Spring MVC HandlerAdapter 详解:处理器适配器的原理与实战

HandlerAdapter(处理器适配器)是 Spring MVC 中连接 DispatcherServletHandler(处理器,如 Controller) 的关键组件。由于 Spring MVC 支持多种 Handler 实现方式(如实现 Controller 接口、HttpRequestHandler 接口、注解驱动的 @Controller 方法),DispatcherServlet 无法直接调用不同类型的 Handler,需通过 HandlerAdapter 进行 “适配”——将统一的调用逻辑转换为具体 Handler 的执行方式,彻底解耦前端控制器与处理器。从 “核心定义→适配器模式→实现类解析→核心流程源码” 四个维度,彻底讲透 HandlerAdapter 的工作机制。

HandlerAdapter 核心定义与设计思想

1. 核心接口与方法

HandlerAdapter 接口定义了所有适配器的通用行为,共 3 个核心方法,覆盖 “适配判断→执行逻辑→资源时间戳” 三大功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface HandlerAdapter {
/**
* 1. 判断当前适配器是否支持指定的 Handler
* @param handler 待适配的处理器(如 Controller 实例、HandlerMethod)
* @return true:支持,可执行;false:不支持
*/
boolean supports(Object handler);

/**
* 2. 执行 Handler 的核心逻辑,返回 ModelAndView(无视图则返回 null)
* @param request HTTP 请求对象
* @param response HTTP 响应对象
* @param handler 待执行的处理器
* @return ModelAndView:封装模型数据与视图名;null:无需视图渲染(如 @ResponseBody 接口)
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

/**
* 3. 获取 Handler 对应资源的最后修改时间(用于缓存控制,如 Last-Modified 请求头)
* @return 时间戳(毫秒);-1:不支持缓存控制
*/
long getLastModified(HttpServletRequest request, Object handler);
}

2. 设计思想:适配器模式

HandlerAdapter 是 适配器模式 的典型应用,核心目标是 “将不同类型的 Handler 统一适配为 DispatcherServlet 可调用的接口”。

阅读全文 »

Spring MVC HandlerMapping 详解:处理器映射器的原理与实战

HandlerMapping 是 Spring MVC 中连接 “HTTP 请求” 与 “处理器(Handler,即 Controller)” 的核心组件,其核心职责是 根据请求的 URL 或其他属性,找到对应的 Handler 及拦截器(Interceptor),并封装为 HandlerExecutionChain 对象返回给 DispatcherServlet。从 “核心定义→实现类对比→配置方式→源码解析” 四个维度,彻底讲透 HandlerMapping 的工作机制。

HandlerMapping 核心定义与作用

HandlerMapping 是一个接口,定义了所有处理器映射器的核心行为,其本质是 “请求→Handler” 的映射器,相当于 MVC 中的 “路由表”。

1. 核心接口方法

1
2
3
4
5
6
7
8
public interface HandlerMapping {
/**
* 根据 HTTP 请求,查找对应的 Handler 及拦截器,封装为 HandlerExecutionChain
* @param request 当前 HTTP 请求
* @return HandlerExecutionChain(包含 Handler + 拦截器),无匹配则返回 null
*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
  • 返回值 HandlerExecutionChain:包含两部分核心内容:
    1. Handler:具体的业务处理器(如 @Controller 类的方法,封装为 HandlerMethod);
    2. HandlerInterceptor 数组:与当前请求匹配的拦截器,按配置顺序存储。

2. 核心数据结构:handlerMap

几乎所有 HandlerMapping 实现类内部都会维护一个 Map<String, Object> 类型的 handlerMap,用于存储 “URL 路径→Handler” 的映射关系,确保请求到来时能快速查找。例如:

1
2
// 以 AbstractUrlHandlerMapping 为例,维护 URL 到 Handler 的映射
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
  • Key:URL 路径(如 /user/list/api/login);
  • Value:Handler 对象(如 UserController 实例、HandlerMethod 实例)。

HandlerMapping 主要实现类与适用场景

HanderMapping继承关系

Spring MVC 提供了多种 HandlerMapping 实现,支持不同的映射策略(如按 Bean 名、按类名、按注解),以下是常用实现类的对比:

阅读全文 »

Spring MVC DispatcherServlet 详解:前端控制器的配置、源码与核心流程

DispatcherServlet 是 Spring MVC 的前端控制器(Front Controller),作为整个框架的入口,统一接收并调度所有 HTTP 请求,协调 HandlerMapping、HandlerAdapter、ViewResolver 等组件完成请求处理与响应生成。其核心价值在于解耦组件依赖,通过 “统一入口 + 策略模式” 让各组件专注于单一职责(如 URL 映射、参数绑定、视图渲染)。从 “配置方式→初始化流程→请求处理流程→核心组件协作” 四个维度,彻底解析 DispatcherServlet 的工作机制。

DispatcherServlet 核心定位与配置

DispatcherServlet 本质是一个标准的 Servlet(继承 HttpServlet),需在 Web 应用中配置才能生效。根据 Servlet 版本不同,分为 web.xml 配置(Servlet 2.5 及以下)和 注解配置(Servlet 3.0+)两种方式。

1. 传统配置:web.xml 方式

通过 web.xml 声明 DispatcherServlet,指定配置文件路径、映射规则及静态资源处理策略,是早期项目的主流配置方式。

完整 web.xml 配置示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="4.0">

<!-- 1. 处理静态资源(避免 DispatcherServlet 拦截 .html 文件) -->
<servlet-mapping>
<servlet-name>default</servlet-name> <!-- 容器默认 Servlet,负责处理静态资源 -->
<url-pattern>*.html</url-pattern> <!-- .html 后缀的请求交给默认 Servlet -->
</servlet-mapping>

<!-- 2. 配置 DispatcherServlet(Spring MVC 前端控制器) -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<!-- 初始化参数:指定 Spring MVC 配置文件路径(默认:/WEB-INF/<servlet-name>-servlet.xml) -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value> <!-- 类路径下的配置文件 -->
</init-param>

<!-- 启动顺序:值为非负整数,容器启动时初始化(值越小优先级越高) -->
<load-on-startup>1</load-on-startup>
</servlet>

<!-- 3. 配置 DispatcherServlet 映射规则 -->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<!-- 映射路径:/ 表示拦截所有未被其他 Servlet 匹配的请求(除 .jsp 外) -->
<url-pattern>/</url-pattern>
</servlet-mapping>

<!-- 4. 可选:配置 ContextLoaderListener(创建根容器,用于业务层 Bean) -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value> <!-- 业务层配置文件 -->
</context-param>
</web-app>
关键配置解析
配置项 作用描述
init-param: contextConfigLocation 指定 Spring MVC 配置文件路径(如 classpath:springmvc.xml),若不配置则默认加载 /WEB-INF/DispatcherServlet-servlet.xml
load-on-startup: 1 容器启动时初始化 DispatcherServlet,避免首次请求时的初始化延迟;值越小,初始化优先级越高
url-pattern: / 拦截所有未被其他 Servlet 匹配的请求(如 /user/list/api/login),但不拦截 .jsp(由 Tomcat 的 JspServlet 处理)
静态资源映射(default Servlet) .html 等静态资源交给容器默认 Servlet 处理,避免 DispatcherServlet 拦截无法解析

2. 现代配置:Servlet 3.0+ 注解方式

Servlet 3.0 规范支持 “无 XML 配置”,Spring 通过 WebApplicationInitializer 接口实现自动注册。只需继承 AbstractAnnotationConfigDispatcherServletInitializer 并实现核心方法,即可替代 web.xml

注解配置示例
阅读全文 »