SpringMVC之源碼分析--HandlerMapping(五)

概述

經過前三章的分析,咱們簡要分析了SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,但對攔截器部分作詳細的分析,攔截器的加載和初始化是三個HandlerMapping相同的部分。本節補充下這塊內容。跨域

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

類圖

類的繼承關係,以下圖:app

咱們知道Spring MVC將請求發送到Handler(Controller)處理器的功能是經過HandlerMapping組件完成的,HandlerMapping組件除了能找到Handler,還對攔截器進行了處理,具體實現是經過AbstractHandlerMapping抽象類完成的。ide

源碼分析

  • HandlerMapping

HandlerMapping接口只定義了一個方法getHandler,其做用是返回請求的處理鏈HandlerExecutionChain,該對象封裝了請求的攔截器以及請求處理Handler,方法定義以下:函數

@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
  • AbstractHandlerMapping

類聲明源碼以下:源碼分析

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
    // ... ...
}

從類的定義可知道,AbstractHandlerMapping抽象類繼承WebApplicationObjectSupport並實現了HandlerMapping和Ordered接口,其中:學習

  • 繼承WebApplicationObjectSupport類提供了上下文ApplicationContext和ServletContext
  • 實現HandlerMapping接口爲咱們提供查找handler處理器功能
  • 實現Ordered接口,以提供排序能力,好比系統中使用多個HandlerMapping,能夠定義每一個HandlerMapping的順序

簡言之,AbstractHandlerMapping類爲咱們提供上下文環境、初始化攔截器並封裝到HandlerExecutionChain對象中。this

該類的入口方法,源代碼以下:url

/**
 * 初始化攔截器
 */
@Override
protected void initApplicationContext() throws BeansException {
    // 提供給子類去重寫的,不過Spring並未去實現
    extendInterceptors(this.interceptors);
    // 加載攔截器
    detectMappedInterceptors(this.adaptedInterceptors);
    // 歸併攔截器
    initInterceptors();
}

/**
 * 空實現
 */
protected void extendInterceptors(List<Object> interceptors) {
}

/**
 * 從上下文中加載MappedInterceptor類型的攔截器,好比咱們在配置文件中使用
 * <mvc:interceptors></mvc:interceptors>
 * 標籤配置的攔截器
 */
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
    mappedInterceptors.addAll(
            BeanFactoryUtils.beansOfTypeIncludingAncestors(
                    obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

/**
 * 合併攔截器,即將<mvc:interceptors></mvc:interceptors>中的攔截器與HandlerMapping中經過屬性interceptors設置的攔截器進行合併
 */
protected void initInterceptors() {
    if (!this.interceptors.isEmpty()) {
        for (int i = 0; i < this.interceptors.size(); i++) {
            Object interceptor = this.interceptors.get(i);
            if (interceptor == null) {
                throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
            }
            // 適配後加入adaptedInterceptors
            this.adaptedInterceptors.add(adaptInterceptor(interceptor));
        }
    }
}

/**
 * 適配HandlerInterceptor和WebRequestInterceptor
 */
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
    if (interceptor instanceof HandlerInterceptor) {
        return (HandlerInterceptor) interceptor;
    }
    else if (interceptor instanceof WebRequestInterceptor) {
        return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
    }
    else {
        throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
    }
}

至此,攔截器初始化完成,接下來咱們分析getHandler方法,源碼以下:spa

/**
 * 返回請求處理的HandlerExecutionChain
 */
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // getHandlerInternal()爲抽象方法,具體需子類實現
    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 = obtainApplicationContext().getBean(handlerName);
    }
    
    // 將請求處理器封裝爲HandlerExectionChain
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    // 對跨域的處理
    if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
}

/**
 * 鉤子函數,需子類實現
 */
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

/**
 * 構建handler處理器的HandlerExecutionChain,包括攔截器
 */
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    // 迭代添加攔截器
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        // 若是攔截器是MappedInterceptor,判斷是否對該handler進行攔截,是的狀況下添加
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else { // HandlerInterceptor直接添加,即經過HandingMapping屬性配置的攔截器
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

總結

本節咱們補充了攔截器的加載初始化過程以及getHandler方法的實現分析,但願對你們有所幫助。

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

相關文章
相關標籤/搜索