一、前言
前文回顾:
数据是怎么从网卡到socket的?
数据是怎么从socket到tomcat的servlet?
本文基于 Spring Boot 3.3.0 与 Spring Framework 6.1.8,旨在追溯一次请求从 Servlet 到 Spring MVC Controller 的完整脉络。我们将回答以下问题:
- 介绍Springboot内嵌tomcat如何产生的?
DispatcherServlet 又是如何被注册到 Tomcat 中的?
- Controller 与
DispatcherServlet 如何建立联系?
- 最终,
DispatcherServlet 又是怎样调用到目标 Controller 的?
二、数据准备
我们从最简单的 Spring Boot 启动类与一个普通的 Controller 开始
@SpringBootApplication
public class App{
public static void main(String[] args){
SpringApplication.run(App.class, args);
}
}
@RestController
@RequestMapping("/testController")
public class TestController{
@ResponseBody
@GetMapping("/getMethod")
public Map<String, Object> getMethod(){
Map<String, Object> result = new HashMap<>();
result.put("aa", 1);
return result;
}
}
三、核心组件的诞生轨迹
我们先通过一张流程图,俯瞰整个 Spring Boot 应用,特别是 Web 相关的核心组件是如何在启动过程中被创建和组装的。

1.ConfigurationClassPostProcessor的注册
- 在web环境下, Springboot启动的时候, 会创建
AnnotationConfigServletWebServerApplicationContext 作为spring的容器(SpringApplication#run -> createApplicationContext())。
- 它的构造过程中初始化了
AnnotatedBeanDefinitionReader,并注册了核心的 ConfigurationClassPostProcessor
ConfigurationClassPostProcessor 是一个 BeanDefinitionRegistryPostProcessor, 负责解析注解配置(@Component、@Configuration、@Import等)。
- 随后是容器准备工作(
prepareContext), 其中会创建主类(App)的beanDefinition注册到容器中。
到这里, 启动主类(App)和用于处理注解的 ConfigurationClassPostProcessor 的 BeanDefinition 就都注册到spring容器中了。
2. WebMvc 相关核心类的装配
2.1 自动装配机制启动
- 在 Spring 容器刷新的过程中(
AbstractApplicationContext#refresh), 有个 invokeBeanFactoryPostProcessors 步骤, 它调用了 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 方法, 它会扫描主类(App) 所在包以及子包下的所有类, 将满足条件的类生成它的beanDefinition, 其中包括 @Component (@RestController 也是一个 @Component)、@Configuration、@Import 引入的类等等...
- 其中
App 类的 @SpringBootApplication 注解上有个 @EnableAutoConfiguration 注解, 它使用 @Import(AutoConfigurationImportSelector.class) 导入了 AutoConfigurationImportSelector, 这个类是自动装配的核心, 它通过spi加载了 META-INF/org.springframework.boot.autoconfigure.AutoConfiguration.import文件 中配置的类。
- 其中在
spring-boot-autoconfigure 项目中的 ...AutoConfiguration.imports 文件中有关web相关的核心内容如下
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
2.2 DispatcherServlet与DispatcherServletRegistrationBean
DispatcherServletAutoConfiguration 注册了两个关键 Bean:
DispatcherServlet: 核心Servlet, 当作分发器
DispatcherServletRegistrationBean: 继承自 ServletContextInitializer,用于将前者注册到 Servlet 容器中 (这里打个标, 下面会用到)
@Configuration(proxyBeanMethods = false)
protected static class DispatcherServletConfiguration{
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties){
DispatcherServlet dispatcherServlet = new DispatcherServlet();
...
return dispatcherServlet;
}
}
@Configuration(proxyBeanMethods = false)
protected static class DispatcherServletRegistrationConfiguration{
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(...){
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
webMvcProperties.getServlet().getPath());
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
return registration;
}
}
2.3 内嵌 Tomcat 工厂
ServletWebServerFactoryAutoConfiguration 引入 EmbeddedTomcat 配置类,定义了 TomcatServletWebServerFactory。 这是内嵌 Tomcat 的构建工厂,负责生成一个最小可运行的 Web 容器。
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ...})
public class ServletWebServerFactoryAutoConfiguration{
...
}
static class EmbeddedTomcat{
@Bean
TomcatServletWebServerFactory tomcatServletWebServerFactory()
...
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
return factory;
}
}
2.4 RequestMappingHandlerMapping和RequestMappingHandlerAdapter
WebMvcAutoConfiguration 的内部类 EnableWebMvcConfiguration 创建了两个核心组件:
RequestMappingHandlerMapping:负责 URL 到方法的映射注册。
RequestMappingHandlerAdapter:负责方法的执行与参数、返回值解析。
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier(“mvcContentNegotiationManager”) ContentNegotiationManager contentNegotiationManager,
@Qualifier(“mvcConversionService”) FormattingConversionService conversionService,
@Qualifier(“mvcValidator”) Validator validator) {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
...
adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
if (jackson2Present) {
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
...
adapter.setCallableInterceptors(configurer.getCallableInterceptors());
adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
return adapter;
}
@Bean
@SuppressWarnings(“deprecation”)
public RequestMappingHandlerMapping requestMappingHandlerMapping(...){
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
initHandlerMapping(mapping, conversionService, resourceUrlProvider);
...
return mapping;
}
到这里, DispatcherServlet, DispatcherServletRegistrationBean, RequestMappingHandlerAdapter, RequestMappingHandlerMapping, TomcatServletWebServerFactory 就会被 ConfigurationClassPostProcessor 处理生成 BeanDefinition 注册到容器中。
四、核心组件的运行时装配
1. SpringBoot 内嵌 Tomcat 的创建
在容器刷新 (AbstractApplicationContext#refresh) 的 onRefresh 阶段,ServletWebServerApplicationContext 会执行 createWebServer() 方法, 如下:
private void createWebServer(){
...
// 这里就是上面EmbeddedTomcat中的的TomcatServletWebServerFactory
ServletWebServerFactory factory = getWebServerFactory();
// 这里创建了一个ServletContextInitializer的匿名内部类, 它很重要
this.webServer = factory.getWebServer(getSelfInitializer());
...
}
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer(){
return this::selfInitialize;
}
private void selfInitialize(ServletContext servletContext) throws ServletException {
// servlet容器的准备工作; 这里将spring上下文(this)添加到了ServletContext中
prepareWebApplicationContext(servletContext);
// 这里将servletContext注入到spring容器中
registerApplicationScope(servletContext);
// 注册servlet环境的几个对象到spring容器中
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
// 这里有DispatcherServletRegistrationBean, 用来将DispatcherServlet注册到ServletContext中
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
public WebServer getWebServer(ServletContextInitializer... initializers){
Tomcat tomcat = new Tomcat();
// …创建 StandardEngine, StandardHost, StandardServer和StandardService, Connector等
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
protected void prepareContext(Host host, ServletContextInitializer[] initializers){
// TomcatEmbeddedContext是StandardContext的子类
TomcatEmbeddedContext context = new TomcatEmbeddedContext();
// 这里就是server.servlet.context-path 配置的项目访问路径
context.setPath(getContextPath());
// 合并ServletContextInitializer
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
// 添加StandardContext
host.addChild(context);
configureContext(context, initializersToUse);
}
protected void configureContext(Context context, ServletContextInitializer[] initializers){
// 将ServletContextInitializer包装到TomcatStarter中,
// 这里TomcatStarter也是一个ServletContainerInitializer
TomcatStarter starter = new TomcatStarter(initializers);
if (context instanceof TomcatEmbeddedContext embeddedContext) {
embeddedContext.setStarter(starter);
embeddedContext.setFailCtxIfServletStartFails(true);
}
// 添加到TomcatEmbeddedContext中(StandardContext的子类)
context.addServletContainerInitializer(starter, NO_CLASSES);
...
}
总结代码部分
- 使用
TomcatServletWebServerFactory 创建内嵌 tomcat (类比成 apache 的 tomcat 中的 Bootstrap 类)
- 初始化
StandardServer、StandardService、Connector、StandardEngine 和 StandardHost 等组件
- 创建
TomcatEmbeddedContext (即 StandardContext 的子类), 代表当前 Web 应用;以前是解析一个 war 包得到一个 StandardContext, Springboot 中就直接创建一个
- 将所有
ServletContextInitializer (包含 DispatcherServletRegistrationBean) 封装进 TomcatStarter
- 最终
TomcatStarter 注册到 TomcatEmbeddedContext, 等待启动时执行
2. DispatcherServlet 的注册
再来看看上面的 getTomcatWebServer 方法的调用 (getWebServer 方法的最后一句), 它直接运行了 start 方法, tomcat 开始启动。
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat){
return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown){
...
initialize();
}
private void initialize() throws WebServerException {
// …
// 开始运行tomcat咯, 底层是server.start(); 会触发initialization
this.tomcat.start();
// …
}
在前文《数据是怎么从socket到tomcat的servlet?》 介绍过 StandardContext 在启动 (start 方法) 的时候会调用 ServletContainerInitializer#onStartup 方法, 所以这里就会调用到上面代码中由函数式接口定义的 ServletContextInitializer 的 selfInitialize 方法。
private void selfInitialize(ServletContext servletContext) throws ServletException {
// servlet容器的准备工作; 这里将spring上下文(this)添加到了ServletContext中
prepareWebApplicationContext(servletContext);
// 这里将servletContext注入到spring容器中
registerApplicationScope(servletContext);
// 注册servlet环境的几个对象到spring容器中
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
// 这里有DispatcherServletRegistrationBean, 用来将DispatcherServlet注册到ServletContext中
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
这里就会执行 DispatcherServletRegistrationBean#onStartup 把 DispatcherServlet 添加到 TomcatEmbeddedContext 中 (StandardContext 的子类)。
3. MVC 组件注入
RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter 注入到 DispatcherServlet
Tomcat 在启动时 (StandardContext#start 方法) 会调用 ServletContainerInitializer#onStartup 方法, 并且随后会调用 Servlet 的 init 方法。而 DispatcherServlet 实现了该方法, 最终会走到 DispatcherServlet 的 onRefresh -> initStrategies 方法中 (这里有 webmvc 的 9 大组件, 只列举我们关心的两个):
protected void initStrategies(ApplicationContext context){
...
initHandlerMappings(context);
initHandlerAdapters(context);
...
}
这里就把 WebMvcAutoConfiguration$EnableWebMvcConfiguration 中创建的 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter 注入到 DispatcherServlet 中了。
4. 将 Controller 对应的方法注册到 RequestMappingHandlerMapping
RequestMappingHandlerMapping 实现了 InitializingBean, 在 afterPropertiesSet() 中:
- 扫描
@Controller 与 @RequestMapping
- 生成
RequestMappingInfo 与 HandlerMethod
- 注册到
MappingRegistry 中
- 形成 URL → 方法的完整映射表
到这里, Tomcat、DispatcherServlet 以及 Controller 对应的 mapping 就全部准备就绪,请求分发链路已经打通。
五、请求分发与执行
当请求 http://localhost:8080/app/testController/getMethod 抵达时, 数据流经以下关键步骤。下图清晰地展示了 DispatcherServlet 处理一个典型请求(参数为 requestBody, 返回 responseBody)的内部流程与组件交互。

DispatcherServlet 调用 RequestMappingHandlerMapping, 根据请求的 url 先获取到 RequestMappingInfo 和 HandlerMethod
- 匹配到拦截器, 构建成一个链式结构
HandlerExecutionChain
- 根据
HandlerMethod 找到 EnableWebMvcConfiguration 中创建的 RequestMappingHandlerAdapter
- 执行前置拦截器
RequestMappingHandlerAdapter#handle 方法中把 handlerMethod 包装成 ServletInvocableHandlerMethod; 设置参数处理器, 返回值处理器
- 参数解析 (
@ModelAttribute、@InitBinder、@ControllerAdvice 等生效)
- 执行目标 controller 的对应的方法
- 随后被返回值处理器处理接口返回值,
ModelAndView 等
- 最后拦截器做后置处理
六、总结
现在回到开篇提出的四个问题,给出结论:
1. Spring Boot 内嵌 Tomcat 是如何产生的?
在应用启动时, AnnotationConfigServletWebServerApplicationContext 会在 onRefresh() 阶段调用 createWebServer(), 通过 TomcatServletWebServerFactory 创建一个内嵌的 Tomcat。 该过程等价于传统 Tomcat 的 Bootstrap 启动逻辑,但以 Bean 的形式完成 Server、Service、Engine、Host、Context 等组件的初始化。
2. DispatcherServlet 是如何被添加到内嵌 Tomcat 中的?
DispatcherServlet 由 DispatcherServletAutoConfiguration 自动装配并注册为 Bean, 同时其对应的 DispatcherServletRegistrationBean 实现了 ServletContextInitializer 接口。当内嵌 Tomcat 启动并触发 onStartup() 回调时, 该注册器将 DispatcherServlet 动态添加到 TomcatEmbeddedContext 中。
3. Controller 又是如何与 DispatcherServlet 建立联系的?
WebMvcAutoConfiguration 提供的 EnableWebMvcConfiguration 在容器刷新阶段生成 RequestMappingHandlerMapping 与 RequestMappingHandlerAdapter, DispatcherServlet 在初始化 (init 方法) 中注入这两个组件, 并通过前者扫描所有 @Controller 与 @RequestMapping, 完成请求路径与处理方法的注册。
4. DispatcherServlet 又是怎样调用到目标 Controller 的?
请求进入后, DispatcherServlet 首先由 HandlerMapping 定位目标方法 (HandlerMethod), 再交由 HandlerAdapter 调用, 经过参数绑定、拦截器链、返回值解析等环节, 最终将执行结果封装为响应对象返回客户端。理解这套复杂的 后端 请求处理机制,对于深入掌握 Spring MVC 和进行有效的故障排查至关重要。如果你有更深入的见解或疑问,欢迎在 云栈社区 与更多开发者交流讨论。