从DispatcherServlet中的doService了解spring组件之间的处理流程

我了解DispatcherServlet中doService函数的目的是简单了解Spring各个组件之间的关系。

DispatcherServlet的父类FrameworkServlet使用processRequest(request, response)函数来处理逻辑。它对request、response对象进行一些处理后,使用doService函数进行处理。

DispatcherServlet 在doService中设置request的相关属性,然后调用doDispatch

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        this.logRequest(request);
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap();
            Enumeration attrNames = request.getAttributeNames();

            label95:
            while(true) {
                String attrName;
                do {
                    if (!attrNames.hasMoreElements()) {
                        break label95;
                    }

                    attrName = (String)attrNames.nextElement();
                } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }

        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
        if (this.flashMapManager != null) {
            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 {
            this.doDispatch(request, response);
        } finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot);
            }

        }

    }

  

DispatcherServlet的doDispatch做了什么呢?它通过handlerMapping获得Handler,然后生成对应的HandlerAdapter来处理数据逻辑(controller层),获得了一个ModelAndView对象。HandlerAdpater 处理的结果是创建了一个ModelAndView对象,但不代表这个ModelAndView对象中包含了完整的信息。  随后DispatcherServlet使用RequestToViewNameResolver给ModelAndView设置viewName。最后调用processDispatchResult来处理界面逻辑(异常和view层)。

    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;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    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);
            }

        }
    }

  

DispatcherServlet的processDispatchResult首先会考虑异常的情况,如果有异常则使用HandlerExceptionResolver来处理异常,随后调用DispatcherServlet的render方法处理界面。

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
        boolean errorView = false;
        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                this.logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException)exception).getModelAndView();
            } else {
                Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
                mv = this.processHandlerException(request, response, handler, exception);
                errorView = mv != null;
            }
        }

        if (mv != null && !mv.wasCleared()) {
            this.render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        } else if (this.logger.isTraceEnabled()) {
            this.logger.trace("No view rendering, null ModelAndView returned.");
        }

        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
            }

        }
    }

  

DispatcherServlet的render方法使用ViewResolver从viewName(ModelAndView中)来得到一个View对象。最后让View对象使用ModelAndView来显示一个界面。

    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
        response.setLocale(locale);
        String viewName = mv.getViewName();
        View view;
        if (viewName != null) {
            view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name ‘" + mv.getViewName() + "‘ in servlet with name ‘" + this.getServletName() + "‘");
            }
        } else {
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name ‘" + this.getServletName() + "‘");
            }
        }

        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Rendering view [" + view + "] ");
        }

        try {
            if (mv.getStatus() != null) {
                response.setStatus(mv.getStatus().value());
            }

            view.render(mv.getModelInternal(), request, response);
        } catch (Exception var8) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Error rendering view [" + view + "]", var8);
            }

            throw var8;
        }
    }

  

总结下:

几个组件之间的执行流程是    handlerMapping  ———》 handlerAdapter————》requestToViewNameResolver ————》handlerExceptionResolver ————》 viewResolver ————》View

原文地址:https://www.cnblogs.com/afraidToForget/p/10102909.html

时间: 2024-10-16 06:02:11

从DispatcherServlet中的doService了解spring组件之间的处理流程的相关文章

在vue中通过使用$attrs实现组件之间的数据传递

组件之间传递数据的方式有很多种,之所以有这么多种方式,是为了满足在不同场景不同条件下的使用. 一般有三种方式: 通过 props 的方式向子组件传递(父子组件) vuex 进行状态管理 非父子组件的通信传递 Vue Event Bus,使用Vue的实例,实现事件的监听和发布,实现组件之间的传递 本文介绍的是使用$attrs的方式. 这个api是在2.4版本中添加的,那么为什么要添加这个特性呢? 看看官网是怎么解释的 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class

Android实现组件之间同步的回调通信

Android开发中,有时会遇到组件之间相互通信回调的问题.一般都是通过Android提供的ResultReceiver来实现(ResultReceiver的使用方法很简单,这里就不多提了). 但之前在工作中,遇到了一个组件间回调的问题,ResultReceiver无法满足需求.简单描述一下问题:service中打开了一个activity,activity需要将一个变量值回调给service,而且这个回调必须是同步的.也就是说activity在确认service接收到了这个变量值后,才能继续向下

非spring组件servlet、filter、interceptor中注入spring bean

问题:在filter和interceptor中经常需要调用Spring的bean,filter也是配置在web.xml中的,请问一下这样调用的话,filter中调用Spring的某个bean,这个bean一定存在吗?现在总是担心filter调用bean的时候,bean还没被实例化? 答案:因为spring bean.filter.interceptor加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 filter 写在 listener 的前面而会先加载 filter.最终得出

Java面试中常问的Spring方面问题(55道含答案)

Spring Framework 现在几乎已成为 Java Web 开发的标配框架.那么,作为 Java 程序员,你对 Spring 的主要技术点又掌握了多少呢?不妨用本文的问题来检测一下. 1.一般问题 1.1. 不同版本的 Spring Framework 有哪些主要功能? VersionFeatureSpring 2.5发布于 2007 年.这是第一个支持注解的版本.Spring 3.0发布于 2009 年.它完全利用了 Java5 中的改进,并为 JEE6 提供了支持.Spring 4.

Java面试中常问的Spring方面问题

Spring Framework 现在几乎已成为 Java Web 开发的标配框架.那么,作为 Java 程序员,你对 Spring 的主要技术点又掌握了多少呢?不妨用本文的问题来检测一下. 1.一般问题 1.1. 不同版本的 Spring Framework 有哪些主要功能? Version FeatureSpring 2.5 发布于 2007 年.这是第一个支持注解的版本.Spring 3.0 发布于 2009 年.它完全利用了 Java5 中的改进,并为 JEE6 提供了支持.Spring

Spring组件扫描&lt;context:component-scan/&gt;使用详解

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/sch

Spring组件扫描&lt;context:component-scan/&gt;使用详解(转)

1.如果不想在xml文件中配置bean,我们可以给我们的类加上spring组件注解,只需再配置下spring的扫描器就可以实现bean的自动载入. <!-- 注解注入 --> <context:annotation-config></context:annotation-config> <context:component-scan base-package="com.liantuo.hotel.common.service.impl" /&g

转 Spring 组件 &lt;context:component-scan base-pakage=&quot;&quot;&gt;用法

1.如果不想在xml文件中配置bean,我们可以给我们的类加上spring组件注解,只需再配置下spring的扫描器就可以实现bean的自动载入. <!-- 注解注入 --> <context:annotation-config></context:annotation-config> <context:component-scan base-package="com.liantuo.hotel.common.service.impl" /&g

spring组件&lt;context:component-scan&gt;详解

上篇文章我们引入注解,在配置中用到了<context:annotation-config/>有助于完全消除Spring配置中的<property>和<constructor-arg>元素,我们仍需要使用<bean>元素显示定义Bean. 但是Spring还有另一种技巧<context:component-scan>元素除了完成与<context:annotation-config>一样的工作,还允许Spring自动检测Bean和定义的