上篇文章把整个MVC的架构和核心流程介绍了一下,其中多次提到DispatcherServlet
整个组件,我们知道整个流程看下来DispatcherServlet
是一个核心组件,接收请求、分发请求给控制器进行处理。这个组件继承自FrameworkServlet
和HttpServlet
,然后与HandlerMapping
,HandlerAdapter
,ViewResolver
等组件,完成了从请求接受到响应返回到完整流程。
如果你去看Spring Framework的参考文档,DispatcherServlet
的主要职责是这样描述的:
- 初始化Web应用程序上下文(WebApplicationContext)和核心组件
- 根据请求路径和方法分派请求到控制器
- 处理视图解析和渲染
- 支持异常处理、国际化、文件上传等高级功能
1. DispatcherServlet 的继承关系与初始化过程
1.1 继承关系
我们可以看到,DispatcherServlet是直接继承FrameworkServlet
然后FrameworkServlet则是继承
HttpServlet
,实现了ApplicationContextAware
接口,这里正好用这个来解释下extends
和implements
的区别。
这里我们可以看到DispatcherServlet extends FrameworkServletBean,意思是:
- 初始化参数注入(initServletBean())
- 处理Servlet生命周期
- 读取初始化参数到Spring的Bean属性里
而implements ApplicationContextAware ,首先这个接口的作用是Spring容器在创建Bean时,把当前ApplicationContext(应用上下文)注入到Bean中。所以实现这个接口的目的是,感知容器实现自定义接口中的方法。
在这里我们可以看出来,extends是继承已有逻辑,implements是遵循外部规范。
1.2 初始化过程
DispatcherServlet
的初始化发生在 Servlet 容器(如 Tomcat)启动时,主要通过 init 方法触发,最终调用 onRefresh 方法完成组件初始化。以下是关键源码分析:
1.2.1 init方法(来自HttpSevletBean)
scala
public abstract class HttpServletBean extends HttpServlet {
@Override
public void init() throws ServletException {
// 设置 Servlet 配置参数
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
bw.setPropertyValues(pvs, true);
// 调用子类的初始化方法
initServletBean();
}
}
这个方法的作用就是将Servlet配置
注入到DispatcherServlet
。
1.2.2 initServletBean
FrameworkServlet 重写了 initServletBean,初始化 Web 上下文:
scala
public abstract class FrameworkServlet extends HttpServletBean {
@Override
protected void initServletBean() throws ServletException {
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
} catch (Exception ex) {
throw new ServletException("Context initialization failed", ex);
}
}
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// 创建或获取 WebApplicationContext
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext) wac);
}
}
if (wac == null) {
wac = createWebApplicationContext(rootContext);
}
// 发布上下文到 ServletContext
if (!this.refreshEventReceived) {
onRefresh(wac);
}
return wac;
}
}
这里主要是调用onRefresh
触发子类的初始化逻辑,关键的点是webApplicationContext
是Spring MVC的IoC容器,管理着MVC的所有相关Bean。
1.2.3 onRefresh方法
这个方法就是要初始化MVC的核心组件:
scss
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
我们在上节讲到的核心组件都是在这里初始化的。
2. 请求分发核心逻辑:doDispatch方法
我们说过DispatcherServlet
还有一个核心职责是处理 HTTP 请求,其请求分发的核心方法是 doDispatch
,位于 DispatcherServlet 类中。以下是 doDispatch
的源码分析:
ini
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 检查是否为 multipart 请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取 HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理 Last-Modified 头部(用于缓存)
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 执行拦截器的 preHandle 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用 HandlerAdapter 处理请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 处理异步请求
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 设置默认视图名(如果未指定)
applyDefaultViewName(processedRequest, mv);
// 执行拦截器的 postHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理结果(视图渲染或异常处理)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
从这个源码能够看出来整个的核心步骤:
检查multipart --> 获取HandlerExceptionChain --> 获取HandlerAdapter --> 处理Last- Modified缓存 --> 执行拦截器preHandler --> 调用HandlerAdapter --> 执行拦截器postHandler --> 处理结果
整个源码的关键是:HandlerExecutionChain
,主要是调用getHandler
遍历所有HandlerMapping
查找匹配的HandlerExecutionChain
(包含Handler和拦截器)。
asyncManager.isConcurrentHandlingStarted()支持异步请求。
3. 总结
这篇文章主要就是说了DispatcherServlet
,DispatcherServlet 是 Spring MVC 的核心调度器,通过初始化九大组件和 doDispatch 方法,协调请求的映射、处理和视图渲染。另外,也可以支持异步处理和异常处理
。