DispatcherServlet浅析
介绍
DispatcherServlet是一个Servlet,在springmvc中被称为前端控制器,根据请求的路径、类型等进行请求的分发。
分析
DispatcherServlet类图

上图中的红色部分为Servlet接口,在Springmvc中实现并扩展了该Servlet接口。在我最早学javaweb开发时,并不是上来就使用各种MVC框架,而是从编写简单的Servlet开始,就是继承HttpServlet后,重写它的service方法。而Springmvc的设计同理,它也继承了HttpServlet并重写它的service方法,同时配置该servlet拦截所有的请求,从而实现了由DispatcherServlet来分发所有的请求。
1. 初始化
因为DispatcherServlet实际上是一个Servlet,所以当配置它生效时它同时也就遵循Servlet的生命周期。在Servlet的生命周期有三个阶段:
init():初始化请求service():获取到请求后的业务处理以及跳转distory():请求处理完成之后的销毁
所以当tomcat容器(servlet容器)启动时,会触发servlet的初始化方法。HttpServletBean实现了该方法。
@Override
public final void init() throws ServletException {
// ...
// 实际的处理在这, 由具体的子类FrameworkServlet实现
initServletBean();
}
FrameworkServlet的initServletBean方法,真正核心的地方在于initWebApplicationContext()
protected final void initServletBean() throws ServletException {
long startTime = System.currentTimeMillis();
try {
// 初始化web容器上下文
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
// ...
}
核心处理方法initWebApplicationContext
- 这个方法的主要逻辑是去调用
onRefresh方法,onRefresh方法在DispatcherServlet类中被覆写,以上面得到的上下文为依托,完成SpringMVC中默认实现类的初始化。 onRefresh方法在DispatcherServlet类中被覆写,所以从这里可以知道先创建spring容器, 在springBean都创建成功之后, 再通过onRefresh方法进行DispatcherServlet的初始化。- 将这个上下文发布到
ServletContext中,也就是将上下文以一个和Servlet类在web.xml中注册名字有关的值为键,设置为ServletContext的一个属性。你可以通过改变publishContext的值来决定是否发布到ServletContext中,默认为true。
protected WebApplicationContext initWebApplicationContext() {
// ...省略部分代码
// 1.
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
// 2.
onRefresh(wac);
}
}
// 3.
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
通过onRefresh(wac)方法,调用到子类DispatcherServlet具体的初始化方法。
初始化DispatcherServlet策略
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
初始化DispatcherServlet策略,分别初始化九大组件(上传组件处理器, 处理器映射器, 理器适配器, 处理器异常整理器, 视图处理器等)
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
2. 分发逻辑

- 当客户端发起请求,请求进入
DispatcherServlet,由它来进行处理器Handler的查找。 - 首先根据请求信息
HttpServletRequest,遍历已注册的所有handlerMappings。返回的结构为HandlerExecutionChain,是包含了具体的处理器handler和拦截器interceptor的结构。 - 获取到
HandlerExcecutionChain后,根据具体的处理器,遍历所有的handlerAdapters,返回支持的HandlerAdapter。 - 在获取到
HandlerAdapter之后,执行具体的handler之前,会先遍历执行HandlerExecutionChain中的拦截器的前置拦截方法preHandle(),若出现某个拦截器的前置方法执行后方法false,则直接从当前节点开始往前执行afterCompletion(),执行完毕后直接终止请求。 - 根据
HandlerAdapter处理器适配器执行具体的处理器Handler逻辑。 - 在执行完成具体的
handler之后,会遍历执行HandlerExecutionChain中拦截器的postHandle方法。 Handler执行完毕之后会返回ModeAndView。- 执行正常的情况下,在渲染模板后,请求返回前,会遍历执行
HandlerExecutionChain中拦截器的afterCompletion方法。
3.设置springmvc容器
根据类图可知DispatcherServlet也是实现了ApplicationContextAware接口,而xxxAware接口,是在springbean初始化时的一个postProcessBeforeInitialization扩展点,由类ApplicationContextAwareProcessor去执行具体的逻辑,简单来说就是将ApplicationContext通过setApplicationContext的方法传递给正在初始化的这个bean。
在springboot中就是通过这个方法,将spring容器(applicationContext)传给DispatcherServlet,待到真正去执行DispatcherServlet的初始化方法时this.applicationContext就不为空,所以在initWebApplicationContext()方法中,就走第一个if的逻辑,这也是springboot最终不会产生父子容器的原因。
转载自:https://juejin.cn/post/7061160723988086797