Spring MVC 是如何将 @RequestMapping 注解映射到对应的 Handler 方法?
Spring MVC 将 @RequestMapping 注解映射到对应的 Handler 方法的过程,主要由 RequestMappingHandlerMapping 这个类来完成。
1. RequestMappingHandlerMapping 的作用:
RequestMappingHandlerMapping是 Spring MVC 中一个关键的HandlerMapping实现。- 它负责维护一个请求映射表,该表存储了
RequestMappingInfo对象与 Handler 方法(Controller 方法)之间的映射关系。 - 当
DispatcherServlet接收到请求时,它会委托RequestMappingHandlerMapping根据请求信息查找匹配的 Handler 方法。
2. RequestMappingHandlerMapping 的初始化:
RequestMappingHandlerMapping实现了InitializingBean接口,它的afterPropertiesSet()方法会在 Spring 容器初始化时被调用。afterPropertiesSet()方法会触发RequestMappingHandlerMapping的初始化过程。
3. 扫描和注册映射关系:
- 扫描 Controller:
RequestMappingHandlerMapping会扫描 Spring 容器中所有带有@Controller或@RequestMapping注解的 Bean。 - 遍历方法: 对于每个 Controller Bean,
RequestMappingHandlerMapping会遍历该 Bean 中的所有方法。 - 解析
@RequestMapping: 对于每个方法,RequestMappingHandlerMapping会检查该方法上是否有@RequestMapping注解(或其变体,如@GetMapping、@PostMapping等)。- 类级别
@RequestMapping: 如果 Controller 类上也有@RequestMapping注解,RequestMappingHandlerMapping会将其与方法级别的@RequestMapping注解进行合并。
- 类级别
- 创建
RequestMappingInfo: 如果找到@RequestMapping注解,RequestMappingHandlerMapping会根据注解的属性值创建一个RequestMappingInfo对象。RequestMappingInfo包含了请求的匹配条件:- PatternsRequestCondition: 包含 URL 路径模式(支持 Ant 风格)。
- RequestMethodsRequestCondition: 包含 HTTP 请求方法(GET、POST 等)。
- ParamsRequestCondition: 包含请求参数条件。
- HeadersRequestCondition: 包含请求头条件。
- ConsumesRequestCondition: 包含请求的 Content-Type 条件。
- ProducesRequestCondition: 包含响应的 Content-Type 条件。
- CustomRequestCondition: 包含自定义的匹配条件(如果有)。
- 注册映射:
RequestMappingHandlerMapping将创建好的RequestMappingInfo对象与对应的 Handler 方法(HandlerMethod对象)关联起来,并注册到内部的映射表中(Map<RequestMappingInfo, HandlerMethod>)。
4. 请求匹配:
- 当
DispatcherServlet接收到一个请求时,它会调用RequestMappingHandlerMapping的getHandler()方法。 getHandler()方法会执行以下步骤:- 创建
HttpServletRequest的包装类: 将HttpServletRequest包装成一个ServletWebRequest对象,方便后续处理。 - 获取请求信息: 从
HttpServletRequest中获取请求的 URL、HTTP 方法、请求参数、请求头等信息。 - 遍历映射表: 遍历
RequestMappingHandlerMapping内部维护的映射表(Map<RequestMappingInfo, HandlerMethod>)。 - 匹配条件: 对于每个
RequestMappingInfo,RequestMappingHandlerMapping会将其中的匹配条件(PatternsRequestCondition、RequestMethodsRequestCondition等)与请求信息进行比较。 - 返回
HandlerExecutionChain: 如果找到匹配的RequestMappingInfo,RequestMappingHandlerMapping会创建一个HandlerExecutionChain对象,其中包含了匹配的 Handler 方法(HandlerMethod)和相关的拦截器(如果有),并将其返回给DispatcherServlet。 - 未找到匹配项: 如果没有找到匹配的
RequestMappingInfo,RequestMappingHandlerMapping会返回null。
- 创建
5. 关键类和方法:
RequestMappingHandlerMapping: 核心类,负责维护请求映射表,并根据请求查找匹配的 Handler 方法。RequestMappingInfo: 包含了请求的匹配条件(URL、方法、参数、请求头等)。HandlerMethod: 封装了 Controller 方法的信息(方法对象、所属的 Bean 对象等)。getHandler():RequestMappingHandlerMapping的方法,根据请求查找匹配的HandlerExecutionChain。afterPropertiesSet():RequestMappingHandlerMapping的初始化方法,在 Spring 容器初始化时被调用,触发扫描和注册映射关系的过程。
总结:
RequestMappingHandlerMapping 通过扫描 @Controller 类和 @RequestMapping 注解,创建 RequestMappingInfo 对象,并将其与 Handler 方法关联起来,注册到内部的映射表中。当接收到请求时,RequestMappingHandlerMapping 会根据请求信息与 RequestMappingInfo 中的匹配条件进行比较,从而找到匹配的 Handler 方法,实现请求的路由和处理。
