@Spring MVC请求处理流程

  大部分java应用都是web应用,展现层是web应用的重要的部分。Spring为展现层提供了一个优秀的Web MVC框架——Spring MVC。它基于MVC的设计理念,此外,它采用了松散耦合、可插拔的组件结构,比其他MVC框架更具扩展性和灵活性。

  SpringMVC通过一套MVC注解,让POJO成为处理请求的处理器,无需实现任何接口,同时,Spring MVC还支持REST风格的URL请求。注解驱动以及REST风格的Spring MVC是Spring的出色功能之一,此外,SpringMVC在数据绑定、视图解析、本地化处理及静态资源处理上都有许多不俗的表现。

在Spring MVC框架中,DispatcherServlet处于核心的位置,它接收所有的请求,负责协调和组织不同组件以完成请求处理返回响应的工作

用过python Django框架的都知道Django对于访问方式的配置就是,一个url路径和一个函数配对,你访问这个url,就会直接调用对应的函数,简单明了。对于java的面向对象来说,就要分两步走。第一步首先要找到是哪个对象,即handler,即我们写的action或是controller。第二步要找到访问的函数,即action中的方法。所以就出现了两个源码接口HandlerMappingHandlerAdapter,前者负责第一步,后者负责第二步。

Spring MVC处理请求的整体过程如下:
1.客户端发出一个HTTP请求,如果这个请求与web.xml中指定的DispatcherServlet的请求映射路径相匹配,web容器就将该请求转交给DispatcherServlet继续处理。
2.DispatcherServlet接收到这个请求后,根据这个请求的信息(比如请求的URL、请求的方式、请求报文头、请求参数等)及HandlerMapping的配置找到处理请求的处理器(Handler)。值得注意的是:Spring MVC中并没有定义一个Handler接口,实际上任何一个Object都可以成为请求处理器。
3.当DispatcherServlet根据HandlerMapping得到对应当前请求的Handler后,通过HandlerAdapter对Handler进行封装,再以统一的适配器接口调用Handler。 HandlerAdapter是Spring MVC的框架级接口,顾名思义,HandlerAdapter是一个适配器,它用统一的接口对各种Handler方法进行调用
4.处理器完成业务逻辑的处理后将返回一个ModelAndView给DispatcherServlet,ModelAndView包含了逻辑视图名和模型数据信息。
5.ModelAndView对象中包含的是"逻辑视图名"而非真正的视图对象,DispatcherServlet通过ViewResolver完成逻辑视图真实视图对象的解析工作。
6.当得到真实的视图对象View后,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染。
7.最终将响应消息返回给客户端,可能是一个普通的HTML页而,也可能是一个XML或JSON串,甚至是一张图片或一个PDF文档等不同的媒体形式。

Spring究竟如何将上下文中的Spring MVC组件Bean装配到DispatcherServlet实例中呢?通过查看DispatcherServlet的initStrategies()方法体中的代码,一切的真相就大白于天下了:

/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet */
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet */
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet */
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet */
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet */
private List<ViewResolver> viewResolvers;
/**
 * Initialize the strategy objects that this servlet uses.
 * <p>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);
}

initStrategies()方法会在DispatcherServlet对应的WebApplicationContext初始化后自动执行,此时Spring上下文中的Bean已经初始化完毕。该方法的工作原理是通过反射机制查找并装配Spring容器中用户显式定义的组件bean,如果找不到,则装配默认的组件实例。

Spring MVC定义了一套默认的组件实现类,也就是说即使不在Spring容器中显式定义组件Bean,也会有一套可用的默认组件出现在DispatcherServlet中。Spring在spring-webmiv.jar包的org/springframework/web/servlet类路径定义了一个DispatcherServlet.properties配置文件,在其中指定了组件的默认组件实现类:

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
    org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,
    org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,
    org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

如果用户希望采用非默认类型的组件,则只需在Spring配置文件中配置自定义的组件Bean就可以,Spring MVC一旦发现上下文中有用户自定义的组件,就不会使用默认的组件了。

看一下Dispatcher中的doDispatcher源码

//前端控制器分派方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        int interceptorIndex = -1;

        try {
            ModelAndView mv;
            boolean errorView = false;

            try {
                   //检查是否是请求是否是multipart(如文件上传),如果是将通过MultipartResolver解析
                processedRequest = checkMultipart(request);
                   //步骤2、请求到处理器(页面控制器)的映射,通过HandlerMapping进行映射
                mappedHandler = getHandler(processedRequest, false);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
                   //步骤3、处理器适配,即将我们的处理器包装成相应的适配器(从而支持多种类型的处理器)
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                  // 304 Not Modified缓存支持
                //此处省略具体代码

                // 执行处理器相关的拦截器的预处理(HandlerInterceptor.preHandle)
                //此处省略具体代码

                // 步骤4、由适配器执行处理器(调用处理器相应功能处理方法)
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                // Do we need view name translation?
                if (mv != null && !mv.hasView()) {
                    mv.setViewName(getDefaultViewName(request));
                }

                // 执行处理器相关的拦截器的后处理(HandlerInterceptor.postHandle)
                //此处省略具体代码
            }
            catch (ModelAndViewDefiningException ex) {
                logger.debug("ModelAndViewDefiningException encountered", ex);
                mv = ex.getModelAndView();
            }
            catch (Exception ex) {
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                mv = processHandlerException(processedRequest, response, handler, ex);
                errorView = (mv != null);
            }

            //步骤5 步骤6、解析视图并进行视图的渲染
//步骤5 由ViewResolver解析View(viewResolver.resolveViewName(viewName, locale))
//步骤6 视图在渲染时会把Model传入(view.render(mv.getModelInternal(), request, response);)
            if (mv != null && !mv.wasCleared()) {
                render(mv, processedRequest, response);
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                            "': assuming HandlerAdapter completed request handling");
                }
            }

            // 执行处理器相关的拦截器的完成后处理(HandlerInterceptor.afterCompletion)
            //此处省略具体代码


        catch (Exception ex) {
            // Trigger after-completion for thrown exception.
            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
            throw ex;
        }
        catch (Error err) {
            ServletException ex = new NestedServletException("Handler processing failed", err);
            // Trigger after-completion for thrown exception.
            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
            throw ex;
        }

        finally {
            // Clean up any resources used by a multipart request.
            if (processedRequest != request) {
                cleanupMultipart(processedRequest);
            }
        }
    }

 

原文地址:https://www.cnblogs.com/winner-0715/p/7198419.html