0%

HandlerAdapter

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 可调用的接口”。

  • 问题场景:DispatcherServlet 只知道调用 HandlerAdapter.handle() 方法,但 Handler 有多种实现(如 ControllerHttpRequestHandlerHandlerMethod),执行方式各不相同(如 handleRequest()service()、反射调用注解方法);
  • 解决方案:每种 Handler 对应一个 HandlerAdapter,适配器内部封装具体的执行逻辑,DispatcherServlet 只需通过适配器调用,无需关心 Handler 类型;
  • 扩展优势:新增 Handler 类型时,只需添加对应的 HandlerAdapter,无需修改 DispatcherServlet 代码(符合开闭原则)。

常用 HandlerAdapter 实现类解析

Spring MVC 提供了多个 HandlerAdapter 实现,分别适配不同类型的 Handler,覆盖从传统接口到现代注解的所有场景。以下是核心实现类的对比与源码解析:

实现类 适配的 Handler 类型 核心执行逻辑 适用场景 优缺点
HttpRequestHandlerAdapter 实现 HttpRequestHandler 接口的类 调用 handler.handleRequest(request, response),无返回值(Handler 自行处理响应) 无需视图渲染的场景(如返回 JSON、文件下载) 轻量灵活,无视图依赖;需手动处理响应流
SimpleControllerHandlerAdapter 实现 Controller 接口的类 调用 handler.handleRequest(request, response),返回 ModelAndView 传统视图驱动项目(如 JSP 页面渲染) 支持视图渲染;接口耦合度高,灵活性低
SimpleServletHandlerAdapter 实现 Servlet 接口的类 调用 handler.service(request, response),无返回值 兼容 legacy Servlet 组件 复用 Servlet 代码;重量级,不符合 MVC 分层
RequestMappingHandlerAdapter 封装注解方法的 HandlerMethod@Controller + @RequestMapping 反射调用注解方法,支持参数绑定、返回值处理(如 @ResponseBody 现代注解驱动项目(主流) 支持复杂参数 / 返回值,灵活性高;逻辑复杂

1. 基础适配器:HttpRequestHandlerAdapter

适配实现 HttpRequestHandler 接口的 Handler,核心是 “Handler 自行处理请求响应”,无需返回 ModelAndView(适合无视图场景)。

源码解析
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
public class HttpRequestHandlerAdapter implements HandlerAdapter {

// 判断是否支持:Handler 是 HttpRequestHandler 类型
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}

// 执行逻辑:调用 Handler 的 handleRequest 方法
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 强转为 HttpRequestHandler,调用其 handleRequest 方法(Handler 自行处理响应)
((HttpRequestHandler) handler).handleRequest(request, response);
return null; // 无视图,返回 null
}

// 缓存控制:支持 LastModified 接口的 Handler,返回资源最后修改时间
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L; // 不支持缓存
}
}
实战示例
1
2
3
4
5
6
7
8
9
10
11
12
13
// 实现 HttpRequestHandler 接口的 Handler
@Component("/download")
public class FileDownloadHandler implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 自行处理响应(如文件下载)
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=test.txt");
try (OutputStream os = response.getOutputStream()) {
os.write("Hello, HttpRequestHandler".getBytes(StandardCharsets.UTF_8));
}
}
}
  • 访问 /download 时,HttpRequestHandlerAdapter 会调用 handleRequest 方法,直接向响应流写入文件内容,无需视图渲染。

2. 传统视图适配器:SimpleControllerHandlerAdapter

适配实现 Controller 接口的 Handler,核心是 “返回 ModelAndView 用于视图渲染”,适合传统 JSP 项目。

源码解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class SimpleControllerHandlerAdapter implements HandlerAdapter {

// 判断是否支持:Handler 是 Controller 类型
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}

// 执行逻辑:调用 Handler 的 handleRequest 方法,返回 ModelAndView
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 强转为 Controller,调用其 handleRequest 方法(返回视图信息)
return ((Controller) handler).handleRequest(request, response);
}

// 缓存控制:支持 LastModified 接口的 Handler
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
实战示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 实现 Controller 接口的 Handler
public class UserController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
// 业务逻辑:查询用户列表
List<String> userList = Arrays.asList("张三", "李四");
// 返回 ModelAndView(视图名 + 模型数据)
ModelAndView mav = new ModelAndView("userList"); // 逻辑视图名:userList → /WEB-INF/views/userList.jsp
mav.addObject("userList", userList);
return mav;
}
}

// XML 配置 Handler
<bean name="/user/list" class="com.example.controller.UserController"/>
  • 访问 /user/list 时,SimpleControllerHandlerAdapter 调用 handleRequest 方法,返回的 ModelAndView 会被视图解析器渲染为 JSP 页面。

3. 兼容适配器:SimpleServletHandlerAdapter

适配实现 Servlet 接口的 Handler,核心是 “复用 legacy Servlet 代码”,适合逐步迁移旧项目时使用。

源码解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SimpleServletHandlerAdapter implements HandlerAdapter {

// 判断是否支持:Handler 是 Servlet 类型
@Override
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}

// 执行逻辑:调用 Servlet 的 service 方法
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 强转为 Servlet,调用其 service 方法(与原生 Servlet 执行逻辑一致)
((Servlet) handler).service(request, response);
return null; // 无视图,返回 null
}

// 不支持缓存控制
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
}
注意事项
  • 该适配器仅用于兼容旧 Servlet 组件,不推荐在纯 Spring MVC 项目中使用(破坏 MVC 分层,Servlet 直接处理请求响应)。

4. 现代核心适配器:RequestMappingHandlerAdapter

RequestMappingHandlerAdapter 是 Spring MVC 3.1+ 引入的核心适配器,专门适配 HandlerMethod(封装 @Controller 类中的 @RequestMapping 方法),支持参数绑定(如 @RequestParam@RequestBody)、返回值处理(如 @ResponseBody)、数据校验(如 @Valid)等现代特性,是当前注解驱动项目的默认适配器。

(1)初始化流程:准备核心组件

RequestMappingHandlerAdapter 实现 InitializingBean 接口,在 Spring 容器初始化时调用 afterPropertiesSet 方法,初始化参数解析器、返回值处理器等核心组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public void afterPropertiesSet() {
// 1. 初始化 @ControllerAdvice 缓存(处理全局异常、全局数据绑定等)
initControllerAdviceCache();

// 2. 初始化参数解析器(处理 @RequestParam、@PathVariable、@RequestBody 等)
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}

// 3. 初始化 initBinder 参数解析器(处理 @InitBinder 方法的参数)
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}

// 4. 初始化返回值处理器(处理 @ResponseBody、ModelAndView、ResponseEntity 等)
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
核心组件说明:
  • HandlerMethodArgumentResolver:参数解析器,负责将 HTTP 请求参数(如 URL 参数、请求体 JSON)绑定到 HandlerMethod 的方法参数(如 @RequestParam String name@RequestBody User user);
  • HandlerMethodReturnValueHandler:返回值处理器,负责将 HandlerMethod 的返回值(如 User 对象、String 视图名)转换为响应(如 JSON 字符串、ModelAndView);
  • @ControllerAdvice 缓存:存储全局增强逻辑(如全局异常处理、全局数据绑定),供参数解析器 / 返回值处理器使用。
(2)请求处理流程:执行 HandlerMethod

RequestMappingHandlerAdapter 的核心逻辑在 handleInternal 方法中,最终通过 invokeHandlerMethod 反射调用注解方法,完成参数绑定、方法执行、返回值处理:

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
// 核心:处理 HandlerMethod 类型的 Handler
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ModelAndView mav;
// 检查请求合法性(如跨域请求预检)
checkRequest(request);

// 会话同步(可选:同一用户会话内串行执行)
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// 无会话同步:直接执行 HandlerMethod
mav = invokeHandlerMethod(request, response, handlerMethod);
}

// 处理缓存控制(如设置 Cache-Control 头)
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
prepareResponse(response);
}
}

return mav;
}
关键方法 invokeHandlerMethod:反射调用注解方法
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
41
42
43
44
45
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

// 1. 封装 Web 请求(便于参数解析)
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 2. 初始化数据绑定工厂(处理 @InitBinder 方法,自定义参数转换)
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

// 3. 初始化 Model 工厂(处理 @SessionAttributes、全局 Model 数据)
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

// 4. 创建可调用的 HandlerMethod(封装参数解析器、返回值处理器)
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); // 参数解析器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); // 返回值处理器
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

// 5. 初始化 ModelAndView 容器(存储模型数据和视图信息)
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); // 读取 FlashMap 数据(重定向参数)
modelFactory.initModel(webRequest, mavContainer, invocableMethod); // 初始化 Model(如 @SessionAttributes 数据)
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

// 6. 处理异步请求(如返回 Callable、DeferredResult)
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

// 7. 反射调用 HandlerMethod 方法(核心:参数绑定→方法执行→返回值处理)
invocableMethod.invokeAndHandle(webRequest, mavContainer);

// 8. 异步处理判断:若异步处理已启动,无需返回 ModelAndView
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

// 9. 构建并返回 ModelAndView(处理模型更新、FlashMap 存储)
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
// 10. 标记请求完成(清理资源)
webRequest.requestCompleted();
}
}
核心步骤拆解:
  1. 参数绑定argumentResolvers 根据方法参数注解(如 @RequestParam),从请求中提取参数并转换为 Java 类型(如 String→Integer);
  2. 方法执行:通过反射调用 @RequestMapping 标注的方法,执行业务逻辑;
  3. 返回值处理returnValueHandlers 根据返回值类型(如 User 对象、String 视图名)或注解(如 @ResponseBody),生成响应(如 JSON 字符串、ModelAndView);
  4. Model 处理:更新 Model 数据(如同步 @SessionAttributes 数据到 Session),构建最终的 ModelAndView(若有视图则渲染,无则返回 null)。

HandlerAdapter 的配置与生效机制

1. 自动配置:mvc:annotation-driven(推荐)

Spring MVC 3.1+ 提供 mvc:annotation-driven 标签,自动注册 RequestMappingHandlerAdapter(以及 RequestMappingHandlerMappingExceptionHandlerExceptionResolver),无需手动配置:

1
2
<!-- springmvc.xml 配置 -->
<mvc:annotation-driven/>
  • 该配置会自动初始化 RequestMappingHandlerAdapter 所需的参数解析器、返回值处理器,支持 @RequestBody@ResponseBody@Valid 等注解。

2. 手动配置(适用于特殊场景)

若需自定义适配器(如扩展参数解析器),可手动在 XML 或 Java 配置中声明:

示例:手动配置 RequestMappingHandlerAdapter 并扩展参数解析器
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
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

// 自定义参数解析器(如处理自定义注解 @CurrentUser)
@Bean
public CurrentUserArgumentResolver currentUserArgumentResolver() {
return new CurrentUserArgumentResolver();
}

// 配置 RequestMappingHandlerAdapter,添加自定义参数解析器
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
// 获取默认参数解析器
List<HandlerMethodArgumentResolver> resolvers = adapter.getDefaultArgumentResolvers();
// 添加自定义参数解析器(优先级高于默认)
List<HandlerMethodArgumentResolver> customResolvers = new ArrayList<>();
customResolvers.add(currentUserArgumentResolver());
customResolvers.addAll(resolvers);
// 设置扩展后的参数解析器
adapter.setArgumentResolvers(customResolvers);
return adapter;
}
}

3. 适配优先级:多个 HandlerAdapter 共存

当容器中存在多个 HandlerAdapter 时,DispatcherServlet 会按以下规则选择:

  1. 按注册顺序遍历:DispatcherServlet 维护 handlerAdapters 列表,按注册顺序依次检查 supports(handler)
  2. 第一个匹配的适配器执行:找到第一个返回 true 的适配器,调用其 handle() 方法;
  3. 优先级控制:通过 Ordered 接口或 order 属性调整优先级(值越小,优先级越高)。

例如:RequestMappingHandlerAdapter 的优先级高于 SimpleControllerHandlerAdapter,确保注解驱动的 Handler 优先被处理。

常见问题与最佳实践

1. 如何自定义参数解析器 / 返回值处理器?

通过 WebMvcConfigureraddArgumentResolvers/addReturnValueHandlers 方法扩展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

// 扩展参数解析器
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CurrentUserArgumentResolver()); // 自定义参数解析器
}

// 扩展返回值处理器
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
handlers.add(new CustomJsonReturnValueHandler()); // 自定义返回值处理器
}
}

2. 最佳实践建议

  1. 优先使用 mvc:annotation-driven:自动注册 RequestMappingHandlerAdapter,无需手动配置,支持现代注解特性;
  2. 避免滥用多个适配器:除非需兼容旧 Handler(如 Controller 接口),否则仅保留 RequestMappingHandlerAdapter,减少适配开销;
  3. 扩展优先于自定义适配器:新增参数绑定或返回值处理逻辑时,优先扩展 HandlerMethodArgumentResolver/HandlerMethodReturnValueHandler,而非自定义 HandlerAdapter;
  4. 理解参数解析器顺序:自定义参数解析器需注意优先级(如 @RequestBody 解析器应优先于 @RequestParam 解析器)。

总结

HandlerAdapter 是 Spring MVC 适配器模式的核心体现,通过 “统一接口 + 不同实现” 解耦 DispatcherServlet 与 Handler,支持多种处理器类型的灵活扩展。其中:

  • 基础适配器HttpRequestHandlerAdapterSimpleControllerHandlerAdapter)适合传统项目,逻辑简单但灵活性低;
  • 核心适配器RequestMappingHandlerAdapter)是现代注解驱动项目的基石,支持参数绑定、返回值处理、数据校验等复杂特性,是实际开发的首选

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10