每次看到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);
- 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类发挥着至关重要的作用,它连接了请求与处理器方法之间的桥梁,是整个请求响应过程的核心。