DispatcherServlet 初始化过程:SpringMVC 的 “启动引擎” 详解
DispatcherServlet 初始化过程:SpringMVC 的 “启动引擎” 详解
DispatcherServlet 是 SpringMVC 的 “前端控制器”,所有 HTTP 请求都先经过它处理,再分发到对应的控制器方法。它的初始化过程决定了 SpringMVC 能否正常工作 —— 从加载配置到初始化核心组件(如 HandlerMapping、ViewResolver),每一步都为后续请求处理打下基础。
本文将拆解 DispatcherServlet 的初始化流程,结合源码逻辑和通俗解释,帮你搞懂它是如何 “启动” 并做好准备的。
一、DispatcherServlet 的类层次:站在巨人的肩膀上
DispatcherServlet 并非孤立存在,它继承了多个抽象类,初始化逻辑分散在父类和自身中。核心继承关系如下:
HttpServlet(Servlet 规范)↓
HttpServletBean(Spring 扩展)↓
FrameworkServlet(SpringMVC 核心)↓
DispatcherServlet(具体实现)
-
HttpServlet:Servlet 规范的基础类,定义了 init()、service() 等生命周期方法;
-
HttpServletBean:将 Servlet 初始化参数(web.xml 或注解配置)绑定到自身属性(如配置文件路径);
-
FrameworkServlet:创建并初始化 SpringMVC 的容器(WebApplicationContext);
-
DispatcherServlet:初始化 SpringMVC 的核心组件(如 HandlerMapping、HandlerAdapter)。
初始化过程就是沿着这个继承链,从父类到子类逐步执行的。
二、初始化核心流程:3 大阶段详解
DispatcherServlet 的初始化始于 Servlet 容器(如 Tomcat)调用 init(ServletConfig) 方法,整个过程可分为 3 个核心阶段:
阶段 1:HttpServletBean 阶段 —— 解析初始化参数
HttpServletBean 是最顶层的 Spring 扩展类,它的核心作用是将 Servlet 配置参数(如 contextConfigLocation)绑定到自身属性,为后续容器初始化做准备。
关键代码与逻辑:
// HttpServletBean 重写 init 方法
@Override
public final void init() throws ServletException {// 1. 解析 web.xml 或注解中的初始化参数(如 <init-param>)PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);// 2. 将参数绑定到当前对象的属性(如 contextConfigLocation)BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);bw.setPropertyValues(pvs, true);// 3. 模板方法:留给子类(FrameworkServlet)实现具体初始化逻辑initServletBean();
}
核心作用:
-
读取配置参数:如 contextConfigLocation(SpringMVC 配置文件路径,如 classpath:springmvc.xml);
-
参数校验与绑定:确保必要参数存在(如配置文件路径),并设置到当前对象的属性中;
-
触发下一阶段:通过 initServletBean() 模板方法,将初始化交给子类 FrameworkServlet。
阶段 2:FrameworkServlet 阶段 —— 创建 WebApplicationContext 容器
FrameworkServlet 是连接 Servlet 和 Spring 容器的关键,它的核心任务是创建并初始化 SpringMVC 的容器(WebApplicationContext),并将其与 Servlet 关联。
WebApplicationContext 是 SpringMVC 专属的容器,通常是 Spring 根容器(Root WebApplicationContext,由 ContextLoaderListener 初始化)的 “子容器”,专门管理控制器(@Controller)、拦截器等 Web 相关的 Bean。
关键代码与逻辑:
// FrameworkServlet 重写 initServletBean 方法
@Override
protected final void initServletBean() throws ServletException {// 1. 初始化 WebApplicationContext(SpringMVC 容器)this.webApplicationContext = initWebApplicationContext();// 2. 模板方法:留给子类(DispatcherServlet)实现后续初始化initFrameworkServlet();
}// 初始化 WebApplicationContext 的核心方法
protected WebApplicationContext initWebApplicationContext() {// 1. 获取父容器(Spring 根容器,通常由 ContextLoaderListener 创建)WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());// 2. 创建当前 Servlet 的 WebApplicationContext(子容器)WebApplicationContext wac = findWebApplicationContext();if (wac == null) {// 若未找到,以根容器为父,创建新的 WebApplicationContextwac = createWebApplicationContext(rootContext);}// 3. 容器初始化完成后,触发 onRefresh 方法(DispatcherServlet 会实现此方法)onRefresh(wac);// 4. 将容器存入 ServletContext,供后续使用ServletContext sc = getServletContext();sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);return wac;
}
核心作用:
-
建立容器层次:以 Spring 根容器为父,创建 SpringMVC 子容器(避免 Web 组件污染全局容器);
-
加载配置文件:根据 contextConfigLocation 加载 SpringMVC 的配置(如扫描 @Controller、定义视图解析器);
-
触发组件初始化:通过 onRefresh(wac) 模板方法,让 DispatcherServlet 初始化核心组件。
阶段 3:DispatcherServlet 阶段 —— 初始化核心组件
DispatcherServlet 是最终的实现类,它在 onRefresh(wac) 方法中完成SpringMVC 核心组件的初始化,这些组件是处理请求的 “关键零件”(如 HandlerMapping、HandlerAdapter)。
关键代码与逻辑:
// DispatcherServlet 重写 onRefresh 方法
@Override
protected void onRefresh(ApplicationContext context) {// 初始化所有核心组件initStrategies(context);
}// 初始化策略(核心组件)
protected void initStrategies(ApplicationContext context) {// 1. 初始化文件上传解析器(处理 multipart/form-data 请求)initMultipartResolver(context);// 2. 初始化本地化解析器(处理国际化)initLocaleResolver(context);// 3. 初始化主题解析器(处理页面主题)initThemeResolver(context);// 4. 初始化 HandlerMapping(映射 URL 到控制器方法)initHandlerMappings(context);// 5. 初始化 HandlerAdapter(执行控制器方法,参数绑定)initHandlerAdapters(context);// 6. 初始化异常处理器(处理控制器方法抛出的异常)initHandlerExceptionResolvers(context);// 7. 初始化请求到视图名的转换器(如控制器返回字符串时转换为视图名)initRequestToViewNameTranslator(context);// 8. 初始化视图解析器(解析视图名到具体视图,如 JSP/Thymeleaf)initViewResolvers(context);// 9. 初始化 FlashMap 管理器(处理重定向时的参数传递)initFlashMapManager(context);
}
核心组件初始化细节:
每个组件的初始化逻辑相似:先从 Spring 容器中查找用户配置的 Bean,若未找到则使用默认实现。以最核心的 HandlerMapping 和 HandlerAdapter 为例:
-
HandlerMapping:
-
- 作用:根据 URL 和请求方法,找到对应的控制器方法(如 @GetMapping (“/user/{id}”) 绑定的方法);
-
- 默认实现:若未配置,会使用 RequestMappingHandlerMapping(支持 @RequestMapping 注解)。
-
HandlerAdapter:
-
- 作用:执行找到的控制器方法,处理参数绑定、类型转换等;
-
- 默认实现:若未配置,会使用 RequestMappingHandlerAdapter(支持 @RequestParam、@PathVariable 等注解)。
三、初始化完成的标志:可以处理请求了
当 initStrategies() 执行完毕,DispatcherServlet 的初始化就完成了。此时:
-
SpringMVC 容器(WebApplicationContext)已创建,包含所有控制器、拦截器等 Bean;
-
核心组件(HandlerMapping、HandlerAdapter 等)已就绪,能处理请求映射、参数绑定、视图渲染等流程;
-
DispatcherServlet 进入 “就绪” 状态,等待接收 Servlet 容器转发的 HTTP 请求(通过 service() 方法处理)。
四、关键问题:初始化失败会怎样?
如果初始化过程中出现错误(如配置文件不存在、组件初始化失败),DispatcherServlet 会抛出 ServletException,导致 Servlet 初始化失败。此时:
-
该 DispatcherServlet 无法处理任何请求;
-
Servlet 容器(如 Tomcat)会在日志中输出错误堆栈,提示具体失败原因(如 “找不到 springmvc.xml”)。
五、总结:DispatcherServlet 初始化的核心价值
DispatcherServlet 的初始化过程本质是 “准备工作”:
-
读取配置(HttpServletBean 阶段);
-
创建容器(FrameworkServlet 阶段);
-
初始化组件(DispatcherServlet 阶段)。
这个过程确保了 SpringMVC 从 “启动” 到 “就绪” 的平滑过渡,为后续处理请求提供了必要的 “基础设施”。理解这个过程,能帮你在遇到初始化失败(如组件缺失、配置错误)时,快速定位问题根源(例如:若 HandlerMapping 未初始化,可能是未开启注解驱动 mvc:annotation-driven/)。
无论是传统 XML 配置还是 Spring Boot 自动配置,DispatcherServlet 的核心初始化逻辑始终不变 —— 这也是 SpringMVC 设计的精妙之处:通过分层抽象,让复杂的初始化过程变得有序且可扩展。