Spring MVC HandlerAdapter 的作用是什么? 为什么 DispatcherServlet 不直接调用 Controller 方法?
HandlerAdapter
在 Spring MVC 中扮演着**适配器(Adapter)**角色。它的核心作用是适配不同类型的处理器。
一、 HandlerAdapter 的核心作用:
-
适配不同类型的 Handler: Spring MVC 支持多种定义 Handler 的方式:
- 目前版本中常用的:使用
@Controller
注解的类中带有@RequestMapping
注解的方法 (HandlerMethod
)。 - 旧式的:实现
org.springframework.web.servlet.mvc.Controller
接口的类。 - 旧式的:实现
org.springframework.web.HttpRequestHandler
接口的类。 - 函数式:
HandlerFunction
(配合RouterFunction
使用)。 - 还有自定义 Handler 类型。
这些不同类型的 Handler,其调用方式、参数解析方式、返回值处理方式都可能不同。DispatcherServlet
本身并不知道如何调用具体的 Handler 类型。
- 目前版本中常用的:使用
-
统一调用接口:
HandlerAdapter
提供了一个统一的接口(handle
方法),DispatcherServlet
只需要调用这个统一的接口,而无需关心底层 Handler 的具体实现细节。HandlerAdapter
内部负责统一调用具体的 Handler 类型。 -
封装调用细节:
HandlerAdapter
不仅仅是简单的调用 Handler 方法,它还负责处理调用过程中的复杂细节,特别是对于注解驱动的HandlerMethod
:- 方法参数解析 (Argument Resolution): 利用
HandlerMethodArgumentResolver
解析 Controller 方法的各种参数(如@RequestParam
,@PathVariable
,@RequestBody
,Model
,HttpServletRequest
等),从请求中提取数据、进行类型转换、数据绑定和校验。 - 方法返回值处理 (Return Value Handling): 利用
HandlerMethodReturnValueHandler
处理 Controller 方法的各种返回值类型(如String
视图名、ModelAndView
、@ResponseBody
对象、ResponseEntity
等),进行视图解析或写入响应体。
- 方法参数解析 (Argument Resolution): 利用
二、 为什么 DispatcherServlet 不直接调用 Controller 方法?
DispatcherServlet
不直接调用 Controller 方法,而是通过 HandlerAdapter
进行调用,主要是基于以下设计原则和考虑:
-
遵循开闭原则 (Open/Closed Principle):
- 对扩展开放: 如果未来 Spring MVC 需要支持一种全新的 Handler 类型,只需要增加一个新的
HandlerAdapter
实现即可,而不需要修改DispatcherServlet
的核心代码。 - 对修改关闭:
DispatcherServlet
的核心调度逻辑保持不变,不用因为 Handler 类型的增多而变化。
- 对扩展开放: 如果未来 Spring MVC 需要支持一种全新的 Handler 类型,只需要增加一个新的
-
保持 DispatcherServlet 的职责单一:
DispatcherServlet
的核心职责是请求的调度和协调,它负责整个请求处理流程的控制。如果让它直接处理各种 Handler 的调用细节(参数解析、返回值处理等),就会违反单一职责原则,使其变得过于庞大和复杂,难以维护。
-
解耦 (Decoupling):
DispatcherServlet
与具体的 Handler 实现解耦。DispatcherServlet
只依赖于HandlerAdapter
接口,不依赖于任何具体的 Controller 或 Handler 实现类。这使得系统更加灵活,组件之间的依赖性更低。
-
提高可测试性:
- 可以独立的测试
DispatcherServlet
的调度逻辑,也可以独立的测试不同的HandlerAdapter
对特定 Handler 类型的适配和调用逻辑。
- 可以独立的测试
-
封装复杂性:
- 调用一个注解驱动的 Controller 方法涉及到很多复杂的操作(反射调用、参数解析、数据绑定、类型转换、校验、返回值处理等)。将这些复杂的逻辑封装在专门的
HandlerAdapter
(如RequestMappingHandlerAdapter
)内部,使得DispatcherServlet
的代码保持简洁。
- 调用一个注解驱动的 Controller 方法涉及到很多复杂的操作(反射调用、参数解析、数据绑定、类型转换、校验、返回值处理等)。将这些复杂的逻辑封装在专门的
总结:
HandlerAdapter
的存在是 Spring MVC 框架灵活性和可扩展性的关键体现。它像一个万能插座转换器一样,允许 DispatcherServlet
这个“电源插座”能够驱动各种不同“插头”(Handler 类型)的“电器”。通过引入 HandlerAdapter
这一层,Spring MVC 实现了对不同处理器类型的统一调度,保持了 DispatcherServlet
的简洁和稳定,并遵循了良好的面向对象设计原则(如开闭原则、单一职责原则),使得框架易于扩展和维护。如果 DispatcherServlet
直接调用 Controller 方法,整个框架的设计将会变得非常脆弱和僵化。