SpringMVC深入:DispatcherServlet

到目前为止,关于SpringMVC的相关内容就学习得差不多了,但是我们在最后还是需要深入了解一下DispatcherServlet底层是如何进行调度的,因此,我们会从源码角度进行讲解。

首先我们需要找到`DispatcherServlet`的最顶层`HttpServletBean`,在这里直接继承的`HttpServlet`,那么我们首先来看一下,它在初始化方法中做了什么:

public final void init() throws ServletException {
    //读取配置参数,并进行配置
    PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
        try {
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
            this.initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        } catch (BeansException var4) {
            if (this.logger.isErrorEnabled()) {
                this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
            }
 
            throw var4;
        }
    }
        //此初始化阶段由子类实现,
    this.initServletBean();
}

我们接着来看`initServletBean()`方法是如何实现的,它是在子类`FrameworkServlet`中定义的: 

protected final void initServletBean() throws ServletException {
    this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " '" + this.getServletName() + "'");
    if (this.logger.isInfoEnabled()) {
        this.logger.info("Initializing Servlet '" + this.getServletName() + "'");
    }
 
    long startTime = System.currentTimeMillis();
 
    try {
        //注意:我们在一开始说了SpringMVC有两个容器,一个是Web容器一个是根容器
        //Web容器只负责Controller等表现层内容
        //根容器就是Spring容器,它负责Service、Dao等,并且它是Web容器的父容器。
        //初始化WebApplicationContext,这个阶段会为根容器和Web容器进行父子关系建立
        this.webApplicationContext = this.initWebApplicationContext();
        this.initFrameworkServlet();
    } catch (RuntimeException | ServletException var4) {
      //...以下内容全是打印日志
}

我们来看看`initWebApplicationContext`是如何进行初始化的: 

 

protected WebApplicationContext initWebApplicationContext() {
    //这里获取的是根容器,一般用于配置Service、数据源等
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
    WebApplicationContext wac = null;
    if (this.webApplicationContext != null) {
        //如果webApplicationContext在之前已经存在,则直接给到wac
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
            if (!cwac.isActive()) {
                if (cwac.getParent() == null) {
                    //设定根容器为Web容器的父容器
                    cwac.setParent(rootContext);
                }
 
                this.configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
 
    if (wac == null) {
        //如果webApplicationContext是空,那么就从ServletContext找一下有没有初始化上下文
        wac = this.findWebApplicationContext();
    }
 
    if (wac == null) {
        //如果还是找不到,直接创个新的,并直接将根容器作为父容器
        wac = this.createWebApplicationContext(rootContext);
    }
 
    if (!this.refreshEventReceived) {
        synchronized(this.onRefreshMonitor) {
            //此方法由DispatcherServlet实现
            this.onRefresh(wac);
        }
    }
 
    if (this.publishContext) {
        String attrName = this.getServletContextAttributeName();
        //把Web容器丢进ServletContext
        this.getServletContext().setAttribute(attrName, wac);
    }
 
    return wac;
}

我们接着来看DispatcherServlet中实现的`onRefresh()`方法: 

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}
     
protected void initStrategies(ApplicationContext context) {
    //初始化各种解析器
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    //在容器中查找所有的HandlerMapping,放入集合中
    //HandlerMapping保存了所有的请求映射信息(Controller中定义的),它可以根据请求找到处理器Handler,但并不是简单的返回处理器,而是将处理器和拦截器封装,形成一个处理器执行链(类似于之前的Filter)
    initHandlerMappings(context);
    //在容器中查找所有的HandlerAdapter,它用于处理请求并返回ModelAndView对象
    //默认有三种实现HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter
    //当HandlerMapping找到处理请求的Controller之后,会选择一个合适的HandlerAdapter处理请求
    //比如我们之前使用的是注解方式配置Controller,现在有一个请求携带了一个参数,那么HandlerAdapter会对请求的数据进行解析,并传入方法作为实参,最后根据方法的返回值将其封装为ModelAndView对象
    initHandlerAdapters(context);
    //其他的内容
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);

DispatcherServlet初始化过程我们已经了解了,那么我们接着来看DispatcherServlet是如何进行调度的,首先我们的请求肯定会经过`HttpServlet`,然后其交给对应的doGet、doPost等方法进行处理,而在`FrameworkServlet`中,这些方法都被重写,并且使用`processRequest`来进行处理:

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //前期准备工作
    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = this.buildLocaleContext(request);
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
    this.initContextHolders(request, localeContext, requestAttributes);
 
    try {
        //重点在这里,这里进行了Service的执行,不过是在DispatcherServlet中定义的
        this.doService(request, response);
    } catch (IOException | ServletException var16) {
        //...
}

请各位一定要耐心,这些大型框架的底层一般都是层层套娃,因为这样写起来层次会更加清晰,那么我们来看看`DispatcherServlet`中是如何实现的:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   //...
    try {
        //重点在这里,这才是整个处理过程中最核心的部分
        this.doDispatch(request, response);
    } finally {
        //...
}

终于找到最核心的部分了: 

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 
    try {
        try {
            ModelAndView mv = null;
            Object dispatchException = null;
 
            try {
                processedRequest = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                //在HandlerMapping集合中寻找可以处理当前请求的HandlerMapping
                mappedHandler = this.getHandler(processedRequest);
                if (mappedHandler == null) {
                    this.noHandlerFound(processedRequest, response);
                    //找不到HandlerMapping则无法进行处理
                    return;
                }
 
                //根据HandlerMapping提供的信息,找到可以处理的HandlerAdapter
                HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = HttpMethod.GET.matches(method);
                if (isGet || HttpMethod.HEAD.matches(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进行处理(我们编写的请求映射方法在这个位置才真正地执行了)
                //HandlerAdapter会帮助我们将请求的数据进行处理,再来调用我们编写的请求映射方法
                //最后HandlerAdapter会将结果封装为ModelAndView返回给mv
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
 
                this.applyDefaultViewName(processedRequest, mv);
                //执行所有拦截器的postHandle()方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var20) {
                dispatchException = var20;
            } catch (Throwable var21) {
                dispatchException = new NestedServletException("Handler dispatch failed", var21);
            }
 
            //最后处理结果,对视图进行渲染等,如果抛出异常会出现错误页面
            this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
        } catch (Exception var22) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
        } catch (Throwable var23) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
        }
 
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
        }
 
    }
}

所以,根据以上源码分析得出最终的流程图 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值