Skip to content

HandlerMapping 与 HandlerAdapter

想象一下:你要寄一个快递,快递员需要知道两个信息:

  1. 这个快递送到哪里(地址)?
  2. 这个快递用什么方式送(飞机、火车、汽车)?

在 Spring MVC 中:

  • HandlerMapping 就是「地址本」,告诉系统「这个请求该由谁处理」
  • HandlerAdapter 就是「交通工具」,告诉系统「用什么方式处理」

HandlerMapping:请求的「地址本」

接口定义

java
public interface HandlerMapping {
    // 根据请求获取处理器执行链
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

返回的 HandlerExecutionChain 包含:

  • 处理器对象(Controller)
  • 拦截器列表

HandlerExecutionChain

java
public class HandlerExecutionChain {
    private final Object handler;  // 处理器,可能是 Controller 或 HandlerMethod
    private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
    
    // 关键方法
    boolean applyPreHandle(HttpServletRequest, HttpServletResponse) throws Exception;
    void applyPostHandle(HttpServletRequest, HttpServletResponse, ModelAndView) throws Exception;
    void triggerAfterCompletion(HttpServletRequest, HttpServletResponse, Exception ex);
}

多种 HandlerMapping 实现

实现类工作方式使用场景
RequestMappingHandlerMapping扫描 @RequestMapping最常用,基于注解的 URL 映射
BeanNameUrlHandlerMappingBean 名称作为 URL简单的 Controller
SimpleUrlHandlerMapping配置文件定义映射需要显式配置的旧项目
ControllerClassNameHandlerMapping类名自动映射RESTful API

RequestMappingHandlerMapping:注解驱动的映射

这是最常用的实现,它会扫描所有 @Controller@RequestMapping 注解:

java
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) { ... }
    
    @PostMapping
    public User createUser(@RequestBody User user) { ... }
    
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) { ... }
    
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) { ... }
}

RequestMappingInfo 封装了映射信息:

java
// RequestMappingInfo 封装了 @RequestMapping 的所有属性
public class RequestMappingInfo {
    private PatternsRequestCondition patternsCondition;  // URL 模式
    private RequestMethodsRequestCondition methodsCondition;  // HTTP 方法
    private ParamsRequestCondition paramsCondition;  // 请求参数
    private HeadersRequestCondition headersCondition;  // 请求头
    private ConsumesRequestCondition consumesCondition;  // 请求 Content-Type
    private ProducesRequestCondition producesCondition;  // 响应 Content-Type
    // ...
}

BeanNameUrlHandlerMapping:简单场景

xml
<!-- Spring XML 配置方式 -->
<bean name="/hello" class="com.example.HelloController"/>
<bean name="/user/list" class="com.example.UserListController"/>
java
// Spring Boot 配置方式
@Configuration
public class WebConfig {
    @Bean("/simple")
    public Controller simpleController() {
        return (request, response) -> {
            response.getWriter().write("Hello");
            return null;
        };
    }
}

SimpleUrlHandlerMapping:显式配置

java
@Configuration
public class UrlConfig {
    @Bean
    public SimpleUrlHandlerMapping handlerMapping() {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        Map<String, Object> urlMap = new HashMap<>();
        urlMap.put("/static/**", staticResourceHttpRequestHandler());
        urlMap.put("/favicon.ico", faviconRequestHandler());
        mapping.setUrlMap(urlMap);
        return mapping;
    }
    
    @Bean
    public StaticResourceHttpRequestHandler staticResourceHttpRequestHandler() {
        return new StaticResourceHttpRequestHandler();
    }
}

HandlerAdapter:处理器的「适配器」

为什么需要 HandlerAdapter?

Controller 可以有多种写法:

java
// 方式一:注解方式(最常用)
@Controller
public class AnnotatedController {
    @RequestMapping("/test")
    public String test() { return "test"; }
}

// 方式二:实现 Controller 接口
public class LegacyController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, 
                                       HttpServletResponse response) {
        return new ModelAndView("legacy");
    }
}

// 方式三:实现 HttpRequestHandler 接口
public class HttpHandlerController implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest request, 
                               HttpServletResponse response) {
        // 直接写入响应,无返回值
        response.getWriter().write("handled");
    }
}

HandlerAdapter 就是为了统一这些不同的处理方式。

接口定义

java
public interface HandlerAdapter {
    // 判断是否支持这个处理器
    boolean supports(Object handler);
    
    // 执行处理器,返回 ModelAndView
    ModelAndView handle(HttpServletRequest request, 
                        HttpServletResponse response, 
                        Object handler) throws Exception;
}

四种内置 HandlerAdapter

Adapter支持类型handle() 返回值
RequestMappingHandlerAdapter@RequestMapping 方法ModelAndView
HttpRequestHandlerAdapterHttpRequestHandlernull(直接写响应)
SimpleControllerHandlerAdapterController 接口ModelAndView
HandlerFunctionAdapter函数式 HandlerFunctionServerResponse

RequestMappingHandlerAdapter:处理注解方法

这是最常用的适配器,处理 @RequestMapping 系列注解:

java
// 核心调用链
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter 
    implements BeanFactoryAware, InitializingBean {

    @Override
    protected ModelAndView handleInternal(HttpServletRequest request,
                                          HttpServletResponse response,
                                          HandlerMethod handlerMethod) throws Exception {
        
        // 1. 检查请求方法是否支持(GET/POST 等)
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes() {
            checkRequiredAttributes(handlerMethod);
        }
        
        // 2. 执行处理器方法
        // 这里会处理参数绑定、返回值处理等
        Object result = invokeHandlerMethod(request, response, handlerMethod);
        
        // 3. 返回 ModelAndView
        return getModelAndView(mavContainer, getDataBinderFactory(handlerMethod), 
                               mavContainer.getModel());
    }
}

SimpleControllerHandlerAdapter:处理 Controller 接口

java
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }

    @Override
    public ModelAndView handle(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler) throws Exception {
        // 直接调用 Controller 的 handleRequest 方法
        return ((Controller) handler).handleRequest(request, response);
    }
}

HttpRequestHandlerAdapter:处理 HttpRequestHandler

java
public class HttpRequestHandlerAdapter implements HandlerAdapter {
    
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof HttpRequestHandler);
    }

    @Override
    public ModelAndView handle(HttpServletRequest request,
                               HttpServletResponse response,
                               Object handler) throws Exception {
        // 调用 handleRequest,但不返回 ModelAndView
        // 响应内容直接在方法内写入
        ((HttpRequestHandler) handler).handleRequest(request, response);
        return null;
    }
}

两者的配合流程

┌─────────────────────────────────────────────────────────────────────────┐
│                      HandlerMapping + HandlerAdapter                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  请求: GET /api/users/123                                               │
│                                                                         │
│      │                                                                  │
│      ▼                                                                  │
│  ┌─────────────────────────────────────┐                               │
│  │  DispatcherServlet                  │                               │
│  │                                     │                               │
│  │  1. getHandler(request)             │                               │
│  └──────────────┬──────────────────────┘                               │
│                 │                                                        │
│                 ▼                                                        │
│  ┌─────────────────────────────────────┐                               │
│  │  HandlerMapping 遍历                │                               │
│  │                                     │                               │
│  │  RequestMappingHandlerMapping        │ ◄── 匹配 /api/users/{id}      │
│  │    └─> 返回 HandlerExecutionChain    │                               │
│  │        (包含 UserController.getUser())│                               │
│  │                                     │                               │
│  └──────────────┬──────────────────────┘                               │
│                 │                                                        │
│                 ▼                                                        │
│  ┌─────────────────────────────────────┐                               │
│  │  DispatcherServlet                  │                               │
│  │                                     │                               │
│  │  2. getHandlerAdapter(handler)       │                               │
│  └──────────────┬──────────────────────┘                               │
│                 │                                                        │
│                 ▼                                                        │
│  ┌─────────────────────────────────────┐                               │
│  │  HandlerAdapter 遍历                 │                               │
│  │                                     │                               │
│  │  RequestMappingHandlerAdapter        │ ◄── supports(UserController) │
│  │    └─> 返回 HandlerAdapter           │                               │
│  │                                     │                               │
│  └──────────────┬──────────────────────┘                               │
│                 │                                                        │
│                 ▼                                                        │
│  ┌─────────────────────────────────────┐                               │
│  │  DispatcherServlet                  │                               │
│  │                                     │                               │
│  │  3. adapter.handle(request, response, handler)                       │
│  │     └─> 返回 ModelAndView            │                               │
│  │                                     │                               │
│  └─────────────────────────────────────┘                               │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

自定义 HandlerMapping

场景:需要基于请求头、参数等条件路由到不同的处理器。

java
// 自定义 HandlerMapping:基于 API 版本
public class VersionBasedHandlerMapping implements HandlerMapping {
    
    @Override
    public HandlerExecutionChain getHandler(HttpServletRequest request) {
        String acceptHeader = request.getHeader("Accept");
        String path = request.getRequestURI();
        
        Object handler = null;
        if (acceptHeader != null && acceptHeader.contains("application/vnd.api.v2+json")) {
            handler = handlerV2Map.get(path);  // v2 版本处理器
        } else {
            handler = handlerV1Map.get(path);  // v1 版本处理器
        }
        
        return handler != null ? new HandlerExecutionChain(handler) : null;
    }
}

自定义 HandlerAdapter

场景:需要支持新的处理器类型。

java
// 自定义 HandlerAdapter:支持 Lambda 表达式作为处理器
public class LambdaHandlerAdapter implements HandlerAdapter {
    
    @Override
    public boolean supports(Object handler) {
        return handler instanceof HandlerFunction;
    }

    @Override
    public ModelAndView handle(HttpServletRequest request,
                               HttpServletResponse response,
                               Object handler) throws Exception {
        HandlerFunction<?> function = (HandlerFunction<?>) handler;
        Object result = function.handle(request);
        
        // 将结果转换为 ModelAndView
        ModelAndView mav = new ModelAndView();
        mav.addObject("result", result);
        mav.setViewName("result");
        return mav;
    }
}

面试追问

Q1: 为什么不把所有 Controller 写成一个类,而是分开写?

分离的好处:

  • 按业务模块组织,代码更清晰
  • 单一职责原则
  • 便于权限控制(不同 Controller 可能需要不同权限)
  • 减少单个文件的大小

Q2: HandlerMapping 和 HandlerAdapter 的顺序重要吗?

重要。在 DispatcherServlet 中,它们是按顺序遍历的:

  • HandlerMapping 找到第一个匹配的
  • HandlerAdapter 找到第一个支持的

如果定义了多个,需要注意 @Order 注解或实现 Ordered 接口。

Q3: Spring 5 的函数式 Web 编程是什么?

Spring 5 引入了函数式路由,使用 RouterFunctionHandlerFunction

java
@Configuration
public class FunctionalWebConfig {
    
    @Bean
    public RouterFunction<ServerResponse> userRouter() {
        return route()
            .GET("/functional/users/{id}", request -> {
                Long id = Long.valueOf(request.pathVariable("id"));
                return ServerResponse.ok().body(User.findById(id));
            })
            .POST("/functional/users", request -> {
                User user = request.body(User.class);
                return ServerResponse.ok().body(User.create(user));
            })
            .build();
    }
}

下节预告HandlerInterceptor 与 Filter 对比 —— 理解拦截器和过滤器的区别,以及各自的使用场景。

基于 VitePress 构建