zoukankan      html  css  js  c++  java
  • spring mvc DispatcherServlet详解之一---处理请求深入解析(续)

    上文中,我们知道分发过程有以下步骤:

    分发过程如下:

    1. 判断是否设置了multipart resolver,设置的话转换为multipart request,没有的话则继续下面的步骤。

    2. 根据当前request,获取hangdler。

    3. 根据当前request,获取HandlerAdapter。

    4. 如果支持http请求头,处理 last-modified header请求头。

    5. 应用已注册interceptor的preHandle方法

    6. HandlerAdapter处理请求。

    7. 设置默认视图。

    8. 应用已注册interceptor的postHandle方法。

    9. 处理异常或者视图渲染。

    这节,我们就详细看看步骤2 步骤3 如何根据request 获取handler 和handlerAdapter。

    根据当前request获取handler,返回HandlerExecutionChain

        /**
         * 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;
        }

    先复习一下handlerMappings是如何获取到的:

                // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
                Map<String, HandlerMapping> matchingBeans =
                        BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
                if (!matchingBeans.isEmpty()) {
                    this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                    // We keep HandlerMappings in sorted order.
                    OrderComparator.sort(this.handlerMappings);
                }

    那么我们来看看如何获取到HandlerExecutionChain的:

        /**
         * Look up a handler for the given request, falling back to the default
         * handler if no specific one is found.
         * @param request current HTTP request
         * @return the corresponding handler instance, or the default handler
         * @see #getHandlerInternal
         */
        @Override
        public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            Object handler = getHandlerInternal(request);
            if (handler == null) {
                handler = getDefaultHandler();
            }
            if (handler == null) {
                return null;
            }
            // Bean name or resolved handler?
            if (handler instanceof String) {
                String handlerName = (String) handler;
                handler = getApplicationContext().getBean(handlerName);
            }
            return getHandlerExecutionChain(handler, request);
        }
    Object handler = getHandlerInternal(request);在AbstractHandlerMapping.java中定义,具体实现有两个:
    AbstractHandlerMethodMapping.java
        /**
         * Look up a handler method for the given request.
         */
        @Override
        protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
            String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
            if (logger.isDebugEnabled()) {
                logger.debug("Looking up handler method for path " + lookupPath);
            }
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            if (logger.isDebugEnabled()) {
                if (handlerMethod != null) {
                    logger.debug("Returning handler method [" + handlerMethod + "]");
                }
                else {
                    logger.debug("Did not find handler method for [" + lookupPath + "]");
                }
            }
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }

    AbstractUrlHandlerMapping.java

        /**
         * Look up a handler for the URL path of the given request.
         * @param request current HTTP request
         * @return the handler instance, or {@code null} if none found
         */
        @Override
        protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
            String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
            Object handler = lookupHandler(lookupPath, request);
            if (handler == null) {
                // We need to care for the default handler directly, since we need to
                // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
                Object rawHandler = null;
                if ("/".equals(lookupPath)) {
                    rawHandler = getRootHandler();
                }
                if (rawHandler == null) {
                    rawHandler = getDefaultHandler();
                }
                if (rawHandler != null) {
                    // Bean name or resolved handler?
                    if (rawHandler instanceof String) {
                        String handlerName = (String) rawHandler;
                        rawHandler = getApplicationContext().getBean(handlerName);
                    }
                    validateHandler(rawHandler, request);
                    handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
                }
            }
            if (handler != null && logger.isDebugEnabled()) {
                logger.debug("Mapping [" + lookupPath + "] to " + handler);
            }
            else if (handler == null && logger.isTraceEnabled()) {
                logger.trace("No handler mapping found for [" + lookupPath + "]");
            }
            return handler;
        }

    给handler创建一个HandlerExecutionChain 

        /**
         * Build a {@link HandlerExecutionChain} for the given handler, including
         * applicable interceptors.
         * <p>The default implementation builds a standard {@link HandlerExecutionChain}
         * with the given handler, the handler mapping's common interceptors, and any
         * {@link MappedInterceptor}s matching to the current request URL. Subclasses
         * may override this in order to extend/rearrange the list of interceptors.
         * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
         * pre-built {@link HandlerExecutionChain}. This method should handle those
         * two cases explicitly, either building a new {@link HandlerExecutionChain}
         * or extending the existing chain.
         * <p>For simply adding an interceptor in a custom subclass, consider calling
         * {@code super.getHandlerExecutionChain(handler, request)} and invoking
         * {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
         * @param handler the resolved handler instance (never {@code null})
         * @param request current HTTP request
         * @return the HandlerExecutionChain (never {@code null})
         * @see #getAdaptedInterceptors()
         */
        protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
            HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                    (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
            chain.addInterceptors(getAdaptedInterceptors());
    
            String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
            for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
    
            return chain;
        }




  • 相关阅读:
    [HAL]5.中断里调用HAL_Delay()进入死循环的原因
    【个人吐槽】C、Delphi、C#、java 摘抄
    【常用软件】木木的常用软件点评(2)------VC程序员常用工具篇
    【下位机软件】平均值滤波之鬼斧神工算法
    【vs2013】如何在VS的MFC中配置使用GDI+?
    【MFC】MFC改变对话框中静态文本的字体大小
    【MFC】VC界面绘制双缓存
    【MFC】如何在MFC创建的程序中更改主窗口的属性 与 父窗口 WS_CLIPCHILDREN 样式 对子窗口刷新的影响 与 窗体区域绘制问题WS_CLIPCHILDREN与WS_CLIPSIBLINGS
    Query的选择器中的通配符[id^='code']或[name^='code']
    获取checkbox数组 里面的值
  • 原文地址:https://www.cnblogs.com/davidwang456/p/4100280.html
Copyright © 2011-2022 走看看