天天看點

初步了解Spring MVC架構必須掌握的AbstractHandlerMethodMapping

作者:馬士兵教育CTO
初步了解Spring MVC架構必須掌握的AbstractHandlerMethodMapping

每次看到Spring MVC架構的源碼,我都能感受到一股莫名的興奮。作為一個資深的後端開發工程師,學習架構源碼是必不可少的一項技能。而AbstractHandlerMethodMapping類無疑是整個Spring MVC架構中最為關鍵和核心的部分之一。在這篇文章中,我将對該類的結構、實作原理進行詳細解析,希望能夠幫助更多的Java開發工程師深入了解Spring MVC架構的運作機制。

AbstractHandlerMethodMapping類是Spring MVC架構中的一個關鍵類,它負責映射處理器方法以及對應的路徑和參數。本文将對該類的源碼進行詳細解析,包括其結構、實作原理等方面。

一、概述

首先我們來看一下AbstractHandlerMethodMapping類的定義:

java複制代碼public abstract class AbstractHandlerMethodMapping<T> extends AbstractMapBasedHandlerMapping {
    ...
}
           

從該定義可以看出,AbstractHandlerMethodMapping類是繼承自AbstractMapBasedHandlerMapping類的,它是一個抽象類,泛型T表示處理器方法的傳回值類型。

AbstractMapBasedHandlerMapping是繼承自AbstractHandlerMapping類的,它也是一個抽象類,主要負責請求與對應處理器的映射。而AbstractHandlerMapping則是繼承自系統資料庫類AbstractResourceBasedMessageSource,實作了HandlerMapping接口,主要負責為請求找到對應的處理器。

是以,AbstractHandlerMethodMapping類是整個處理器映射的核心,它在Spring MVC架構中發揮着重要作用。

二、結構

接下來我們來看一下AbstractHandlerMethodMapping類的結構:

java複制代碼public abstract class AbstractHandlerMethodMapping<T> extends AbstractMapBasedHandlerMapping {

    private final Map<T, HandlerMethod> handlerMethods = new HashMap<>();

    @Nullable
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        ...
    }
    
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        ...
    }
    
    protected abstract boolean isHandler(Class<?> beanType);
    
    protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
    
    protected abstract T getMappingForUrl(String urlPath);
    
    protected abstract void registerHandlerMethod(Object handler, Method method, T mapping);
    
    ...
}
           

該類包含了handlerMethods、lookupHandlerMethod、getHandlerInternal、isHandler、getMappingForMethod、getMappingForUrl、registerHandlerMethod等重要方法。下面我們逐一進行解析。

1. handlerMethods

handlerMethods是一個Map類型的屬性,它存儲了T類型到HandlerMethod類型的映射關系。其中,T是處理器方法的辨別符,可以是任意類型,比如路徑、URL等;HandlerMethod則是一個封裝了處理器方法、參數等資訊的對象。

java複制代碼private final Map<T, HandlerMethod> handlerMethods = new HashMap<>();
           

2. lookupHandlerMethod

lookupHandlerMethod方法用于查找與請求路徑和請求方法比對的處理器方法。具體實作方式可參考以下代碼:

java複制代碼@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    List<T> directPathMatches = getDirectPathMatches(lookupPath);
    if (directPathMatches != null) {
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        addMatchingMappings(getPatternMatches(lookupPath), matches, request);
    }
    if (!matches.isEmpty()) {
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            if (logger.isTraceEnabled()) {
                logger.trace("Found multiple matches among " + matches +
                        " according to " + comparator + ", returning " + bestMatch.handlerMethod);
            }
        }
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    } else {
        return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
    }
}
           

首先,該方法會分别擷取與請求路徑完全比對以及模式比對的處理器方法,然後根據請求方法、請求頭、請求參數等資訊進行比對。

如果找到了多個處理器方法,則通過比較器進行排序,選擇最佳比對。最終,該方法傳回比對的處理器方法。

3. getHandlerInternal

getHandlerInternal方法是AbstractMapBasedHandlerMapping中的抽象方法,在AbstractHandlerMethodMapping中進行了實作。

該方法的作用是根據請求路徑和請求方法找到對應的處理器方法,并傳回封裝後的HandlerExecutionChain對象。具體實作方式如下:

java複制代碼protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request, LOOKUP_PATH);
    ...
    HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
    ...
    return new HandlerExecutionChain(handlerMethod);
}
           

4. isHandler

isHandler方法是一個抽象方法,由子類進行實作。它用于判斷某個bean是否是一個處理器,如果是則傳回true,否則傳回false。具體實作方式取決于不同的子類。

java複制代碼protected abstract boolean isHandler(Class<?> beanType);
           

5. getMappingForMethod

getMappingForMethod方法也是一個抽象方法,由子類進行實作。它用于擷取處理器方法的辨別符T。具體實作方式取決于不同的子類,可能是請求路徑、URL等。

java複制代碼protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
           

6. getMappingForUrl

GetMappingForUrl方法也是一個抽象方法,由子類進行實作。它用于根據URL擷取處理器方法的辨別符T。具體實作方式取決于不同的子類。

java複制代碼protected abstract T getMappingForUrl(String urlPath);
           
  1. registerHandlerMethod

registerHandlerMethod方法用于注冊處理器方法。該方法會根據處理器類型和處理器方法的辨別符,将其添加到handlerMethods中。

java複制代碼protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    HandlerMethod handlerMethod = createHandlerMethod(handler, method);
    handlerMethods.put(mapping, handlerMethod);
}
           

以上就是AbstractHandlerMethodMapping類的基本結構。接下來,我們将對該類的具體實作原理進行解析。

三、實作原理

AbstractHandlerMethodMapping類的主要作用是映射處理器方法,它通過維護一個Map類型的handlerMethods變量,将處理器方法的辨別符T與HandlerMethod對象建立映射。

在Spring MVC架構中,處理器方法可以是任意的Java方法,通常是由@Controller或@RestController注解修飾的。當Web應用接收到HTTP請求時,DispatcherServlet會根據請求路徑和請求方法,找到與之比對的處理器方法。

具體的比對過程就是通過lookupHandlerMethod方法實作的。該方法首先擷取所有與請求路徑完全比對的處理器方法,然後再擷取所有模式比對的處理器方法。調用addMatchingMappings方法,将所有比對的映射關系添加到matches清單中。

然後,根據請求方法、請求頭、請求參數等資訊,對matches清單進行篩選,并選擇最佳比對,最終傳回比對的HandlerMethod對象。

registerHandlerMethod方法用于注冊處理器方法,它通過createHandlerMethod方法建立一個HandlerMethod對象,并将其添加到handlerMethods中。HandlerMethod對象封裝了處理器方法的詳細資訊,包括bean、參數、傳回值等。

熟讀源碼後,你會發現 AbstractHandlerMethodMapping 類中應用了模闆方法模式、工廠方法模式和政策模式等多種設計模式。這些設計模式的使用有效地降低了代碼的耦合度、提高可維護性,為Spring MVC架構的優秀設計提供了有力支援。

在源碼實作中,AbstractHandlerMethodMapping類采用了以下設計模式:

1. 模闆方法模式

AbstractHandlerMethodMapping類中的getHandlerInternal和lookupHandlerMethod方法就使用了模闆方法模式。這兩個方法都是繼承自AbstractMapBasedHandlerMapping類的抽象方法,在AbstractHandlerMethodMapping中進行了具體實作。這種模闆方法模式使得子類可以根據自身需要實作這些方法,并且共享了父類的通用邏輯。

2. 工廠方法模式

AbstractHandlerMethodMapping類的registerHandlerMethod方法中使用了工廠方法模式。它通過調用createHandlerMethod方法建立HandlerMethod對象,并将其添加到handlerMethods變量中。createHandlerMethod是一個工廠方法,用于建立HandlerMethod對象,并對其屬性進行初始化。這種工廠方法模式使得建立HandlerMethod對象的過程與具體實作分離,增加了代碼的可維護性。

3. 政策模式

在lookupHandlerMethod方法中,Spring MVC架構采用了政策模式,利用Comparator接口進行最佳比對的選擇。具體來說,MatchComparator類就是一個比較器政策,用于根據不同的比較規則排序matches清單中的元素。這種政策模式使得比對過程的具體實作可以在運作時動态切換和定制,提高了比對效率和靈活性。

四、小結一下

AbstractHandlerMethodMapping類是整個處理器映射的核心,它通過handlerMethods變量維護了處理器方法的映射關系,通過lookupHandlerMethod方法實作了處理器方法與請求路徑的比對。 該類還包含了isHandler、getMappingForMethod、getMappingForUrl、registerHandlerMethod等重要方法,它們的實作原理取決于不同的子類。

在Spring MVC架構中,AbstractHandlerMethodMapping類發揮着至關重要的作用,它連接配接了請求與處理器方法之間的橋梁,是整個請求響應過程的核心。

繼續閱讀