SpringMVC之源碼分析--HandlerAdapter(二)

概述

本章咱們主要分析Spring處理HandlerAdapter組件的處理流程以及其接口源碼。歸納來講,Spring使用HandlerAdapter組件分爲兩步,首先是註冊組件,其次是處理用戶請求,如下針對這兩個過程進行詳細的分析。java

本系列文章是基於Spring5.0.5RELEASE。ios

註冊HandlerAdapter

通常狀況下,在使用Spring MVC時,咱們會配置在應用啓動時加載和初始化Spring MVC組件,也就是在部署描述文件中配置<load-on-startup>1</load-on-startup>,啓動過程會最終調用到DispatcherServlet的initStrategies(context)方法,此方法即爲初始化九大組件的入口,固然也包括咱們今天說要分析的HandlerAdapter,源碼以下:web

/**
 * 初始化策略對象
 */
protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    // 初始化處理器適配器HandlerAdapter
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

private void initHandlerAdapters(ApplicationContext context) {
    this.handlerAdapters = null;
    // 在部署描述文件中可控制該參數
    if (this.detectAllHandlerAdapters) {
        // 從應用上下文中查找HandlerAdapter
        Map<String, HandlerAdapter> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<>(matchingBeans.values());
            // 對使用的HandlerAdapter進行排序,spring提供的只有RequestMappingHandlerAdapter實現了Ordered接口,其餘都不具有排序功能
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    }
    else {
        try {
            // 若是在部署描述文件中配置了detectAllHandlerAdapters=false,此時spring會加載名稱爲handlerAdapter的bean爲處理器適配器
            HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
            // 轉化爲集合賦給handlerAdapters屬性
            this.handlerAdapters = Collections.singletonList(ha);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerAdapter later.
        }
    }

    // 若是未配置HandlerAdapter,註冊默認的處理器適配器,即從DispatcherServlet.properties中獲取的HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter和ReqeustMappingHandlerAdapter
    if (this.handlerAdapters == null) {
        this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        if (logger.isDebugEnabled()) {
            logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
        }
    }
}

以上就是Spring MVC對HandlerAdapter組件的註冊過程。spring

處理請求

應用在啓動時完成了HandlerAdapter的註冊,即具有了處理用戶請求的能力,那麼在用戶發起請求時,請求會有DispatcherSerlvlet所攔截,最終調用其doDispatch方法進行處理,源碼以下:app

/**
 * 處理請求分發給handler
 */
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 {
            // 附件上傳有關,後續分析multipartResolver時再詳細分析
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 獲取請求處理的HandlerExecutionChain對象,該對象組裝了咱們的handler和相關攔截器
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 獲取請求處理的處理器適配器,在getHandlerAdapter方法中進行適配策略的判斷
            // 參加下面getHandlerAdapter的方法詳解
            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;
            }

            // 調用handler處理方法,由此,經過適配器模式就調用到了咱們使用的handler的處理方法
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", 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);
            }
        }
    }
}

/**
 * 返回handler對象的處理器適配器
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        // 迭代處理器適配器策略,判斷handler是否適配成功
        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");
}

以上就是HandlerAdatper處理用戶請求源碼分析。async

接口分析

經過前面兩部分,咱們分析了Spring MVC對HandlerAdapter組件的使用,包括註冊和處理請求過程,接下來咱們看一下給接口的定義,源碼以下:源碼分析

package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;

public interface HandlerAdapter {
    
    /**
     * 判斷適配器是否適配handler,適配策略由子類實現
     */
    boolean supports(Object handler);

    /*
     * 使用適配的handler執行用戶請求
     */
    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    /**
     * 返回資源的最後修改時間,若是handler實現類不支持能夠返回-1
     */
    long getLastModified(HttpServletRequest request, Object handler);

}

以上是HandlerAdapter接口的源碼分析,如需自定義HandlerAdapter,只須要實現該接口,在supports方法中定義適配策略,並實現handle方法進行調用便可。post

總結

本文主要分析了Spring MVC使用HandlerAdapter組件處理用戶請求的過程,從過程來看,用戶可干預的也就是實現HanderApater接口,自定義處理器適配器。學習

接下來的幾章將分析Spring MVC提供的HandlerAdapter適配策略,但願本節對你們能有幫助,謝謝。this

最後建立了qq羣方便你們交流,可掃描加入,同時也可加我qq:276420284,共同窗習、共同進步,謝謝!

相關文章
相關標籤/搜索