Spring MVC启动与请求处理全流程解析:从DispatcherServlet到HandlerAdapter

一、Spring MVC概述与启动流程

1.1 Spring MVC在Spring Boot中的角色

虽然Spring Boot简化了配置,但其底层仍然使用Spring MVC处理Web请求。传统方式通过web.xml配置DispatcherServlet,而在Spring Boot中则通过自动配置完成。

1.2 DispatcherServlet初始化流程

Tomcat启动时:

  1. 创建DispatcherServlet对象

  2. 调用其init()方法

  3. init()中创建Spring容器,并添加ContextRefreshListener

  4. Spring容器刷新完成后触发ContextRefreshedEvent

  5. 执行initStrategies()初始化九大组件

复制代码
protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);    // 核心
    initHandlerAdapters(context);    // 核心
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

二、Handler与HandlerMapping详解

2.1 四种Handler类型

Spring MVC支持四种处理器:

  1. 实现Controller接口的Bean

    复制代码
    @Component("/test")
    public class MyController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest request, 
                                          HttpServletResponse response) {
            return new ModelAndView();
        }
    }
  2. 实现HttpRequestHandler接口的Bean

    复制代码
    @Component("/test")
    public class MyHttpHandler implements HttpRequestHandler {
        @Override
        public void handleRequest(HttpServletRequest request, 
                                  HttpServletResponse response) {
            // 直接操作request/response
        }
    }
  3. @RequestMapping注解的方法(最常用)

    复制代码
    @RestController
    public class MyController {
        @GetMapping("/test")
        public String test(String username) {
            return "Hello " + username;
        }
    }
  4. HandlerFunction对象(函数式Web)

    复制代码
    @Bean
    public RouterFunction<ServerResponse> router() {
        return route()
            .GET("/test", request -> ok().body("Hello"))
            .build();
    }

2.2 三种HandlerMapping及其工作原理

1. BeanNameUrlHandlerMapping
  • 负责处理ControllerHttpRequestHandler接口的实现类

  • 查找逻辑:

    复制代码
    // 简化逻辑
    for (String beanName : beanFactory.getBeanNamesForType(Object.class)) {
        if (beanName.startsWith("/")) {
            handlerMap.put(beanName, beanFactory.getBean(beanName));
        }
    }
2. RequestMappingHandlerMapping
  • 负责处理@RequestMapping注解的方法

  • 查找流程:

    1. 扫描所有Bean类型

    2. 判断是否有@Controller@RequestMapping注解

    3. 解析类和方法上的@RequestMapping

    4. 封装为RequestMappingInfo -> HandlerMethod映射

    5. 存入registry(Map结构)

3. RouterFunctionMapping
  • 负责处理RouterFunction及其包含的HandlerFunction

  • 建立路径到HandlerFunction的映射

2.3 Handler查找流程

复制代码
// DispatcherServlet中的查找逻辑
protected HandlerExecutionChain getHandler(HttpServletRequest request) {
    for (HandlerMapping mapping : this.handlerMappings) {
        HandlerExecutionChain handler = mapping.getHandler(request);
        if (handler != null) {
            return handler;  // 找到即返回,遍历顺序决定优先级
        }
    }
    return null;
}

优先级顺序(默认):

  1. BeanNameUrlHandlerMapping

  2. RequestMappingHandlerMapping

  3. RouterFunctionMapping

这意味着如果同一个路径被多种Handler处理,先注册的生效。


三、HandlerAdapter与执行适配

3.1 为什么需要HandlerAdapter?

不同类型的Handler执行方式不同:

  • Controller:调用handleRequest()

  • HttpRequestHandler:调用handleRequest()

  • HandlerMethod:反射调用对应方法

  • HandlerFunction:调用handle()

HandlerAdapter采用适配器模式,统一调用接口。

3.2 四种HandlerAdapter

1. HttpRequestHandlerAdapter
复制代码
public boolean supports(Object handler) {
    return (handler instanceof HttpRequestHandler);
}

public ModelAndView handle(HttpServletRequest request, 
                          HttpServletResponse response, Object handler) {
    ((HttpRequestHandler) handler).handleRequest(request, response);
    return null;
}
2. SimpleControllerHandlerAdapter
复制代码
public boolean supports(Object handler) {
    return (handler instanceof Controller);
}

public ModelAndView handle(HttpServletRequest request,
                          HttpServletResponse response, Object handler) {
    return ((Controller) handler).handleRequest(request, response);
}
3. RequestMappingHandlerAdapter
复制代码
public final boolean supports(Object handler) {
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

这是最复杂的Adapter,负责执行@RequestMapping方法。

4. HandlerFunctionAdapter
复制代码
public boolean supports(Object handler) {
    return handler instanceof HandlerFunction;
}

3.3 适配器查找流程

复制代码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    for (HandlerAdapter adapter : this.handlerAdapters) {
        if (adapter.supports(handler)) {
            return adapter;  // 找到支持该Handler的Adapter
        }
    }
    throw new ServletException("No adapter for handler [" + handler + "]");
}

四、方法参数解析器(HandlerMethodArgumentResolver)

4.1 参数注解与数据来源

注解 数据来源 解析器
@RequestParam 请求参数 RequestParamMethodArgumentResolver
@RequestHeader 请求头 RequestHeaderMethodArgumentResolver
@SessionAttribute Session属性 SessionAttributeMethodArgumentResolver
@RequestAttribute Request属性 RequestAttributeMethodArgumentResolver
@RequestBody 请求体 RequestResponseBodyMethodProcessor
无注解(简单类型) 请求参数 RequestParamMethodArgumentResolver

4.2 参数解析流程

复制代码
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
    if (result == null) {
        // 遍历所有解析器
        for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
            if (resolver.supportsParameter(parameter)) {
                result = resolver;
                this.argumentResolverCache.put(parameter, result);
                break;
            }
        }
    }
    return result;
}

注意 :解析器有顺序,先匹配的先使用。例如@RequestParam@SessionAttribute优先级高。

4.3 RequestParam解析示例

复制代码
// RequestParamMethodArgumentResolver的核心逻辑
protected Object resolveName(String name, MethodParameter parameter, 
                            NativeWebRequest request) {
    // 1. 尝试从Multipart请求获取
    Object arg = resolveMultipartArgument(name, parameter, request);
    
    // 2. 从普通请求参数获取
    if (arg == null) {
        String[] paramValues = request.getParameterValues(name);
        if (paramValues != null) {
            arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
        }
    }
    return arg;
}

五、方法返回值处理器(HandlerMethodReturnValueHandler)

5.1 返回值处理类型

返回值类型 处理器 说明
@ResponseBody RequestResponseBodyMethodProcessor 将返回值写入响应体
String(无@ResponseBody ViewNameMethodReturnValueHandler 作为视图名进行视图解析
Model ModelMethodProcessor 添加到Model中
ModelAndView ModelAndViewMethodReturnValueHandler 直接返回ModelAndView

5.2 @ResponseBody处理流程

RequestResponseBodyMethodProcessor使用HttpMessageConverter将返回值转换为HTTP响应。

5.3 常用HttpMessageConverter

  1. ByteArrayHttpMessageConverter:字节数组

  2. StringHttpMessageConverter:字符串(默认ISO-8859-1编码)

  3. SourceHttpMessageConverter:XML源

  4. MappingJackson2HttpMessageConverter:JSON转换(需添加Jackson依赖)

5.4 中文乱码解决方案

方案一:在@RequestMapping中指定

复制代码
@RequestMapping(path = "/test", produces = "application/json;charset=UTF-8")
@ResponseBody
public String test() {
    return "中文";
}

方案二:自定义StringHttpMessageConverter

复制代码
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        StringHttpMessageConverter converter = new StringHttpMessageConverter();
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        converters.add(0, converter); // 添加到最前面
    }
}

方案三:添加JSON Converter

复制代码
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = 
            new MappingJackson2HttpMessageConverter();
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        converters.add(converter);
    }
}

六、完整请求处理流程

6.1 流程图概述

复制代码

6.2 源码关键节点

  1. DispatcherServlet.doDispatch():请求分发入口

  2. AbstractHandlerMapping.getHandler():获取HandlerExecutionChain

  3. RequestMappingHandlerAdapter.invokeHandlerMethod():执行@RequestMapping方法

  4. HandlerMethodArgumentResolverComposite.resolveArgument():解析所有参数

  5. RequestResponseBodyMethodProcessor.handleReturnValue():处理@ResponseBody返回值


七、总结与最佳实践

7.1 核心组件关系

  • HandlerMapping:路由映射,建立路径到Handler的映射

  • HandlerAdapter:执行适配,统一不同Handler的调用方式

  • HandlerMethodArgumentResolver:参数解析,从请求中提取数据

  • HandlerMethodReturnValueHandler:返回值处理,将结果转换为HTTP响应

7.2 性能优化建议

  1. 合理使用Handler类型 :优先使用@RequestMapping,它最灵活且功能最全

  2. 减少反射调用:避免在Controller中使用过多的动态参数

  3. 合理配置MessageConverter:只添加需要的Converter,减少遍历开销

  4. 利用缓存:Spring MVC会缓存参数解析器、返回值处理器等

7.3 常见问题排查

  1. 404问题:检查HandlerMapping是否正常注册,路径映射是否正确

  2. 参数绑定失败:检查参数解析器是否支持该参数类型

  3. 中文乱码:检查StringHttpMessageConverter编码设置

  4. 返回值处理异常:检查是否缺少对应的HttpMessageConverter

7.4 扩展点

  • 自定义HandlerMapping :实现HandlerMapping接口

  • 自定义HandlerAdapter :实现HandlerAdapter接口

  • 自定义参数解析器 :实现HandlerMethodArgumentResolver

  • 自定义返回值处理器 :实现HandlerMethodReturnValueHandler

相关推荐
小途软件13 小时前
用于机器人电池电量预测的Sarsa强化学习混合集成方法
java·人工智能·pytorch·python·深度学习·语言模型
Echo娴13 小时前
Spring的开发步骤
java·后端·spring
吴声子夜歌13 小时前
Java数据结构与算法——基本数学问题
java·开发语言·windows
_UMR_14 小时前
springboot集成Jasypt实现配置文件启动时自动解密-ENC
java·spring boot·后端
程序员小假14 小时前
我们来说说 Cookie、Session、Token、JWT
java·后端
短剑重铸之日15 小时前
《SpringBoot4.0初识》第一篇:前瞻与思想
java·开发语言·后端·spring·springboot4.0
蓝色王者15 小时前
springboot 2.6.13 整合flowable6.8.1
java·spring boot·后端
Tao____15 小时前
基于Ruoyi开发的IOT物联网平台
java·网络·物联网·mqtt·网络协议