DispatcherServlet浅析

DispatcherServlet浅析_第1张图片

介绍

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

分析

DispatcherServlet类图

DispatcherServlet浅析_第2张图片

​ 上图中的红色部分为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 {

    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
        try {
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        }catch (BeansException ex) {
            if (logger.isErrorEnabled()) {
                logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
            }
            throw ex;
        }
    }
    
    // 实际的处理在这, 由具体的子类FrameworkServlet实现
    initServletBean();
}
复制代码

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

protected final void initServletBean() throws ServletException {
    long startTime = System.currentTimeMillis();
    try {
        // 初始化web容器上下文
        this.webApplicationContext = initWebApplicationContext();
        initFrameworkServlet();
    }catch (ServletException | RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        throw ex;
    }
    // ...
}
复制代码

核心处理方法initWebApplicationContext

protected WebApplicationContext initWebApplicationContext() {
    // ...省略部分代码
    // 这个方法的主要逻辑是去调用onRefresh(ApplicationContext context)方法,onRefresh方法在DispatcherServlet类中被覆写,
    // 以上面得到的上下文为依托,完成SpringMVC中默认实现类的初始化。
    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            // onRefresh方法在DispatcherServlet类中被覆写,所以从这里可以知道先创建spring容器, 在springBean都创建成功之后, 再通过onRefresh方法进行DispatcherServlet的初始化。
            onRefresh(wac);
        }
    }

    // 将这个上下文发布到ServletContext中,也就是将上下文以一个和Servlet类在web.xml中注册名字有关的值为键,设置为ServletContext的一个属性。你可以通过改变
    // publishContext的值来决定是否发布到ServletContext中,默认为true。
    if (this.publishContext) {
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }
    return wac;
}
复制代码

通过onRefresh(wac)方法,调用到子类DispatcherServlet具体的初始化方法。

/**
    * 初始化DispatcherServlet策略
    *
    * This implementation calls {@link #initStrategies}.
    */
@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

/**
    * 初始化DispatcherServlet策略(九大组件)
    *
    * Initialize the strategy objects that this servlet uses.
    * 

May be overridden in subclasses in order to initialize further strategy objects. */ 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浅析_第3张图片

  • 当客户端发起请求,请求进入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最终不会产生父子容器的原因。

你可能感兴趣的:(前端,mvc,java,后端,程序人生)