zoukankan      html  css  js  c++  java
  • SpringMVC系列之主要组件

    一、组件说明

    1. DispatcherServlet:前端控制器,用于请求到达前端控制器,由它调用其他组件处理用户的请求。
    2. HandlerMapping:处理器映射器,负责根据用户请求找到Handler(处理器),springmvc提供了不同的映射器实现方式。
    3. Handler:处理器,对具体的用户请求进行处理。
    4. HandlerAdapter:处理器适配器,通过HandlerAdapter对处理器进行执行。
    5. View Resolver:视图解析器,负责将处理结果生成view视图。View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。

    二、前端控制器

      DispatcherServlet是springmvc的中央调度器,DispatcherServlet创建时会默认从DispatcherServlet.properties文件加载springmvc所用的各种组件。

      

       

    二、处理器映射器

      处理器映射器负责根据request请求找到对应的Handler处理器以及Interceptor拦截器,将它们封装在HandlerExecutionChain对象中返回给前端控制器。

      下面是两种常用的处理器映射器:

      1、BeanNameURLHandlerMapping:根据请求的url与spring容器中定义的bean的name进行匹配,从而从spring容器中找到bean实例。

      

      2、simpleURLHandlerMapping:它可以将url和处理器bean的id进行统一映射配置。

      

    三、处理器适配器

      HandlerAdapter会根据适配器接口对Handler进行包装适配,包装后即可对处理器进行执行(使用了适配器模式)。

      下面是两种常用的处理器适配器:

      1、SimpleControllerHandlerAdapter:简单控制器处理器适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的bean通过此适配器进行适配执行。

      

      2、HttpRequestHandlerAdapter:http请求处理器适配器,所有实现了org.springframework.web.HttpRequestHandler接口的bean通过此适配器进行适配执行。

      

      注:处理器实现HttpRequestHandler接口,实现handleRequest方法,该方法没有返回、ModelAndView,可以通过response修改定义响应内容,比如返回json数据。

      

    四、注解处理器映射器和适配器

      

      可以使用组件扫描,而省去在spring容器中配置每个controller类。配置如下:

        <context:component-scan base-package="com.demo.ssm.controller"></context:component-scan>

      1、注解处理器映射器,对类中标记的@RequestMapping的方法进行映射,根据RequestMapping定义的url匹配RequestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器。

    <!-- 注解映射器 -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

      2、注解处理器适配器,对标记的@RequestMapping的方法进行适配。

    <!-- 注解适配器 -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

      注:还可以使用下面的配置代替上面处理器映射器和适配器的配置:

       <mvc:annotation-driven></mvc:annotation-driven>

    五、总结

      springmvc处理流程:

      1、用户发送请求到DispatchServlet前端控制器。

    /**
         * Process the actual dispatching to the handler.
         * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
         * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
         * to find the first that supports the handler class.
         * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
         * themselves to decide which methods are acceptable.
         * @param request current HTTP request
         * @param response current HTTP response
         * @throws Exception in case of any kind of processing failure
         */
        protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HttpServletRequest processedRequest = request;
            HandlerExecutionChain mappedHandler = null;
            boolean multipartRequestParsed = false;
    
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
            try {
                ModelAndView mv = null;
                Exception dispatchException = null;
    
                try {
                    processedRequest = checkMultipart(request);
                    multipartRequestParsed = (processedRequest != request);
    
                    // Determine handler for the current request.
                    mappedHandler = getHandler(processedRequest);
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        noHandlerFound(processedRequest, response);
                        return;
                    }
    
                    // Determine handler adapter for the current request.
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                    // Process last-modified header, if supported by the handler.
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if (logger.isDebugEnabled()) {
                            logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                        }
                        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
    
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
    
                    // Actually invoke the handler.
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
    
                    applyDefaultViewName(request, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                }
                catch (Exception ex) {
                    dispatchException = ex;
                }
                processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            }
            catch (Exception ex) {
                triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
            }
            catch (Error err) {
                triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
            }
            finally {
                if (asyncManager.isConcurrentHandlingStarted()) {
                    // Instead of postHandle and afterCompletion
                    if (mappedHandler != null) {
                        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                    }
                }
                else {
                    // Clean up any resources used by a multipart request.
                    if (multipartRequestParsed) {
                        cleanupMultipart(processedRequest);
                    }
                }
            }
        }
    View Code

      2、DispatchServlet调用HandlerMapping处理器映射器根据url查找Handler。

    /**
         * Return the HandlerExecutionChain for this request.
         * <p>Tries all handler mappings in order.
         * @param request current HTTP request
         * @return the HandlerExecutionChain, or {@code null} if no handler could be found
         */
        protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            for (HandlerMapping hm : this.handlerMappings) {
                if (logger.isTraceEnabled()) {
                    logger.trace(
                            "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
                }
                HandlerExecutionChain handler = hm.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
            return null;
        }
    View Code

      3、DispatchServlet调用HandlerAdapter处理器适配器对HandlerMapping找到的Handler进行包装。

    /**
         * Return the HandlerAdapter for this handler object.
         * @param handler the handler object to find an adapter for
         * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
         */
        protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
            for (HandlerAdapter ha : this.handlerAdapters) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Testing handler adapter [" + ha + "]");
                }
                if (ha.supports(handler)) {
                    return ha;
                }
            }
            throw new ServletException("No adapter for handler [" + handler +
                    "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
        }
    View Code

      4、执行Handler,并返回一个ModelAndView。

    /**
         * Determine an error ModelAndView via the registered HandlerExceptionResolvers.
         * @param request current HTTP request
         * @param response current HTTP response
         * @param handler the executed handler, or {@code null} if none chosen at the time of the exception
         * (for example, if multipart resolution failed)
         * @param ex the exception that got thrown during handler execution
         * @return a corresponding ModelAndView to forward to
         * @throws Exception if no error ModelAndView found
         */
        protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
                Object handler, Exception ex) throws Exception {
    
            // Check registered HandlerExceptionResolvers...
            ModelAndView exMv = null;
            for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
                exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
                if (exMv != null) {
                    break;
                }
            }
            if (exMv != null) {
                if (exMv.isEmpty()) {
                    request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
                    return null;
                }
                // We might still need view name translation for a plain error model...
                if (!exMv.hasView()) {
                    exMv.setViewName(getDefaultViewName(request));
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
                }
                WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
                return exMv;
            }
    
            throw ex;
        }
    View Code

      5、DispatchServlet调用ViewResolver视图解析器进行视图解析,解析完成后返回一个View,再进行视图渲染并展示。

    /**
         * Render the given ModelAndView.
         * <p>This is the last stage in handling a request. It may involve resolving the view by name.
         * @param mv the ModelAndView to render
         * @param request current HTTP servlet request
         * @param response current HTTP servlet response
         * @throws ServletException if view is missing or cannot be resolved
         * @throws Exception if there's a problem rendering the view
         */
        protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
            // Determine locale for request and apply it to the response.
            Locale locale = this.localeResolver.resolveLocale(request);
            response.setLocale(locale);
    
            View view;
            if (mv.isReference()) {
                // We need to resolve the view name.
                view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
                if (view == null) {
                    throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                            "' in servlet with name '" + getServletName() + "'");
                }
            }
            else {
                // No need to lookup: the ModelAndView object contains the actual View object.
                view = mv.getView();
                if (view == null) {
                    throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                            "View object in servlet with name '" + getServletName() + "'");
                }
            }
    
            // Delegate to the View object for rendering.
            if (logger.isDebugEnabled()) {
                logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
            try {
                view.render(mv.getModelInternal(), request, response);
            }
            catch (Exception ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
                            getServletName() + "'", ex);
                }
                throw ex;
            }
        }
    View Code

      

  • 相关阅读:
    浅谈MapReduce
    Redis源码分析(三十五)--- redis.c服务端的实现分析(2)
    Redis源码分析(三十五)--- redis.c服务端的实现分析(2)
    Redis源码分析(三十五)--- redis.c服务端的实现分析(2)
    Confluence 6 手动安装语言包和找到更多语言包
    Confluence 6 安装一个语言组件
    Confluence 6 启用主题评论
    Confluence 6 启用远程 API
    Confluence 6 配置时间和日期格式
    Confluence 6 创建-使用-删除快捷链接
  • 原文地址:https://www.cnblogs.com/xujian2014/p/5435471.html
Copyright © 2011-2022 走看看