likes
comments
collection
share

DispatcherServlet浅析

作者站长头像
站长
· 阅读数 41

介绍

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

分析

DispatcherServlet类图

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();
}

FrameworkServletinitServletBean方法,真正核心的地方在于initWebApplicationContext()

protected final void initServletBean() throws ServletException {
    long startTime = System.currentTimeMillis();
    try {
        // 初始化web容器上下文
        this.webApplicationContext = initWebApplicationContext();
        initFrameworkServlet();
    }
    // ...
}

核心处理方法initWebApplicationContext

  1. 这个方法的主要逻辑是去调用onRefresh方法,onRefresh方法在DispatcherServlet类中被覆写,以上面得到的上下文为依托,完成SpringMVC中默认实现类的初始化。
  2. onRefresh方法在DispatcherServlet类中被覆写,所以从这里可以知道先创建spring容器, 在springBean都创建成功之后, 再通过onRefresh方法进行DispatcherServlet的初始化。
  3. 将这个上下文发布到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浅析

  • 当客户端发起请求,请求进入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
评论
请登录