SpringMVC DispatcherServlet执行流程及源码分析

本文详细分析了SpringMVC DispatcherServlet的执行流程,从用户请求到响应的全过程,包括DispatcherServlet如何处理请求,查找HandlerMapping,执行HandlerAdapter,以及视图解析。文中还涉及到源码解读,帮助理解SpringMVC架构的稳定性和低耦合性。
摘要由CSDN通过智能技术生成

你要知道的SpringMVC DispatcherServlet执行流程及源码分析都在这里

转载请注明出处 http://blog.csdn.net/u014205968/article/details/78184424

本系列文章主要根据源码讲解SpringMVC的启动过程,以及相关重要组件的源码分析。阅读此系列文章需要具备Spring以及SpringMVC相关知识。本文将分以下几篇文章进行讲解,读者可按需查阅。

DispatcherServlet执行流程及相关源码分析

在前一篇文章SpringMVC 启动流程及相关源码分析中,详细探讨了Spring MVCWeb容器中部署后的启动过程,以及相关源码分析,同时也讨论了DispatcherServlet类的初始化创建过程,相关内容在此不再赘述,如有需求可查阅。

本文主要讲解DispatcherServlet类获取用户请求到响应的全过程,并针对相关源码进行分析。对于基本的MVC架构本文不再进行讲解,有需要的读者可自行查阅。

首先,让我们站在Spring MVC的四大组件:DispatcherServletHandlerMappingHandlerAdapter以及ViewResolver的角度来看一下Spring MVC对用户请求的处理过程,有如下时序图:

DispatcherServlet执行序列图

具体处理过程如下:

  • 1、用户请求发送至DispatcherServlet类进行处理。
  • 2、DispatcherServlet类遍历所有配置的HandlerMapping类请求查找Handler
  • 3、HandlerMapping类根据request请求URL等信息查找能够进行处理的Handler,以及相关拦截器interceptor并构造HandlerExecutionChain
  • 4、HandlerMapping类将构造的HandlerExecutionChain类的对象返回给前端控制器DispatcherServlet类
  • 5、前端控制器拿着上一步的Handler遍历所有配置的HandlerAdapter类请求执行Handler
  • 6、HandlerAdapter类执行相关Handler并获取ModelAndView类的对象。
  • 7、HandlerAdapter类将上一步Handler执行结果的ModelAndView 类的对象返回给前端控制器。
  • 8、DispatcherServlet类遍历所有配置的ViewResolver类请求进行视图解析。
  • 9、ViewResolver类进行视图解析并获取View对象。
  • 10、ViewResolver类向前端控制器返回上一步骤的View对象。
  • 11、DispatcherServlet类进行视图View的渲染,填充Model
  • 12、DispatcherServlet类向用户返回响应。

通过时序图和上面的讲解不难发现,整个Spring MVC对于用户请求的响应和处理都是以DispatcherServlet类为核心,其他三大组件均与前端控制器进行交互,三大组件之间没有交互并且互相解耦,因此,三大组件可以替换不同的实现而互相没有任何影响,提高了整个架构的稳定性并且降低了耦合度。接下来会按照上述的响应过程逐一进行讲解。

DispatcherServlet类本质上依旧是一个Servlet并且其父类实现了Servlet接口,我们知道,Servlet执行Service()方法对用户请求进行响应,根据前一篇文章的分析方法可以得到人如下的调用逻辑图:

service方法调用逻辑

从上图的源码调用逻辑可以看出,HttpServlet抽象类实现了Servlet接口service(ServletRequest, ServletResponse)的方法,因此,用户请求的第一执行方法为该方法,该方法紧接着直接调用了service(HttpServletRequest, HttpServletResponse)方法,其子类FrameworkServlet抽象类重写了该方法,因为多态的特性最终是调用了FrameworkServlet抽象类service(HttpServletRequest, HttpServletResponse)方法,FrameworkServlet抽象类同样也重写了doHead()doPost()doPut()doDelete()doOptions()doTrace()方法,service(ServletRequest, ServletResponse)方法根据请求类型的不同分别调用上述方法,上述六个方法都调用了processRequest()方法,而该方法最终调用了DispatcherServlet类doService()方法。通过层层分析,我们找到了最终要调用的处理用户请求的方法,doService()之前的方法调用都比较简单,这里不再逐一来查看源码,有兴趣的读者可以自行查阅。

查看doService()的源码如下:

    /**
     * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
     * for the actual dispatching.
     */
    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (logger.isDebugEnabled()) {
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
            logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                    " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
        }

        // Keep a snapshot of the request attributes in case of an include,
        // to be able to restore the original attributes after the include.
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap<String, Object>();
            Enumeration<?> attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }

        // Make framework objects available to handlers and view objects.
        /*
        将当前Servlet的子IoC容器放入request请求中
        由此,我们可以访问到当前IoC子容器以及根IoC容器中的Bean
        */
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

        try {
            //真正进行用户请求的处理
            doDispatch(request, response);
        }
        fina
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值