HandlerMapping
一系列组件主要功能是获取处理器执行链HandlerExecutionChain,也就是获取处理器(controller)和拦截器HandlerInterceptor。
HandlerMapping
一系列组件里面主要的思路是
匹配处理器的逻辑:
@RequestMapping
注解的方法收集在一个注册表,注册表里面有很多个map,比如以URL为ke y,以Controller实体和具体方法为value的map。我们以现在常用的使用注解@RequestMapping的涉及的实现类进行解释
HandlerMapping :该接口也表明组件的关键功能就是用来匹配最合适的处理器(Controller)和拦截器HandlerInterceptor
AbstractHandlerMapping :该抽象类主要提供如果没有获取到合适的处理器则赋值一个默认的处理器,和将合适的拦截器进行收集
AbstractHandlerMethodMapping : 该抽象类主要将全部的Controller里面的是处理器的方法进行收集到注册表中,做了几个map,用于请求的信息去匹配合适的处理器(Controller)
RequestMappingInfoHandlerMapping :该抽象类主要复写handleMatch
和
handleNoMatch`方法,将匹配或者没有匹配的不同情况进行一些具体处理
RequestMappingHandlerMapping : 该实体类主要用来判断是否是标明@Controller
或 @RequestMapping
的处理器,和将@RequestMapping
里面的信息构建在RequestMappingInfo存储,最后就是初始化一些匹配处理器(Controller)需要的一些辅助类
HandlerMapping接口主要作用就是用来获取处理器执行链HandlerExecutionChain,HandlerExecutionChain里面的属性也就是处理器handler(controller)和拦截器(HandlerInterceptor)。
//org.springframework.web.servlet.HandlerMapping HandlerExecutionChain getHandler(HttpServletRequest request) throws Except 复制代码
HandlerExecutionChain 主要用来存储处理器(controller)和拦截器,查看属性即可明白,同时用来执行拦截器的方法。首先是获取拦截器,然后一些拦截器的方法的执行。
属性
//org.springframework.web.servlet.HandlerExecutionChain //处理器 private final Object handler; //初始化HandlerExecutionChain存储拦截器的对象 @Nullable private HandlerInterceptor[] interceptors; //将拦截器数组interceptors转换成list @Nullable private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1; 复制代码
拦截器的获取
构造器初始化添加拦截器
//org.springframework.web.servlet.HandlerExecutionChain /** * 初始化拦截器 * @param handler * @param interceptors */ public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) { if (handler instanceof HandlerExecutionChain) { HandlerExecutionChain originalChain = (HandlerExecutionChain) handler; this.handler = originalChain.getHandler(); this.interceptorList = new ArrayList<>(); CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList); CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList); } else { this.handler = handler; this.interceptors = interceptors; } } 复制代码
add方法添加拦截器
//org.springframework.web.servlet.HandlerExecutionChain //add方法添加拦截器都先init InterceptorList public void addInterceptor(HandlerInterceptor interceptor) { initInterceptorList().add(interceptor); } public void addInterceptor(int index, HandlerInterceptor interceptor) { initInterceptorList().add(index, interceptor); } public void addInterceptors(HandlerInterceptor... interceptors) { if (!ObjectUtils.isEmpty(interceptors)) { CollectionUtils.mergeArrayIntoCollection(interceptors, initInterceptorList()); } } 复制代码
//org.springframework.web.servlet.HandlerExecutionChain /** * 如果interceptorList先初始化 * @return */ private List<HandlerInterceptor> initInterceptorList() { if (this.interceptorList == null) { this.interceptorList = new ArrayList<>(); if (this.interceptors != null) { // An interceptor array specified through the constructor CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList); } } this.interceptors = null; return this.interceptorList; } 复制代码
拦截器的方法
applyPreHandle
方法
//org.springframework.web.servlet.HandlerExecutionChain boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; //如果执行preHandle失败,则需要将执行成功的拦截器执行afterCompletion if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; } 复制代码
//org.springframework.web.servlet.HandlerExecutionChain void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { //倒序执行执行成功的拦截器的afterCompletion方法 for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } } 复制代码
applyPostHandle
方法
//org.springframework.web.servlet.HandlerExecutionChain void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } } 复制代码
该抽象类主要获取处理器的一个骨架方法,同时提供如果没有获取到合适的处理器则赋值一个默认的处理器,和将合适的拦截器进行收集。而匹配最合适的处理器(Controller)的方法getHandlerInternal
作为一个抽象方法给子类进行实现。
getHandler
方法获取HandlerExecutionChain,这个就是骨架方法
调用getHandlerInternal
获取最合适的处理器(Controller),该方法是抽象方法,由子类进行实现获取
调用 getDefaultHandler
获取默认的处理器
调用 getHandlerExecutionChain
将匹配成功的拦截器存储在 HandlerExecutionChain
// org.springframework.web.servlet.handler.AbstractHandlerMapping public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //获取handler(controller) Object handler = getHandlerInternal(request); if (handler == null) { // 获取默认handler handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } // 获取handler(controller)和拦截器(HandlerInterceptor) HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (logger.isTraceEnabled()) { logger.trace("Mapped to " + handler); } else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) { logger.debug("Mapped to " + executionChain.getHandler()); } if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) { CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); config = (config != null ? config.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; } 复制代码
复制代码
调用getHandlerExecutionChain
获取HandlerExecutionChain,遍历全部拦截器,将匹配成功的拦截器添加到HandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { //将拦截器添加到HandlerExecutionChain chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { //将拦截器添加到HandlerExecutionChain chain.addInterceptor(interceptor); } } return chain; } 复制代码
其中遍历的来源从[^] 属性作为入口进行了解
属性:拦截器
// org.springframework.web.servlet.handler.AbstractHandlerMapping /** * 主要用来通过{@link #initInterceptors()}方法将{@link #interceptors}初始化到{@link #adaptedInterceptors} * 而初始化{@link #interceptors}则通过{@link #setInterceptors(Object...)} 和{@link #extendInterceptors(List)} */ private final List<Object> interceptors = new ArrayList<>(); /** * 拦截器 */ private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>(); 复制代码
属性interceptors
的初始化方法
// org.springframework.web.servlet.handler.AbstractHandlerMapping public void setInterceptors(Object... interceptors) { this.interceptors.addAll(Arrays.asList(interceptors)); } 复制代码
// org.springframework.web.servlet.handler.AbstractHandlerMapping protected void extendInterceptors(List<Object> interceptors) { } 复制代码
属性interceptors
的用途
// org.springframework.web.servlet.handler.AbstractHandlerMapping 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"); } this.adaptedInterceptors.add(adaptInterceptor(interceptor)); } } } 复制代码
// org.springframework.web.servlet.handler.AbstractHandlerMapping 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()); } } 复制代码
拦截器接口主要是三个方法,而这三个方法的执行时间在整体执行流程里面可以查看,不赘述
preHandle
/** * 执行时间在{@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)}执行之前 */ default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } 复制代码
postHandle
/** * 执行时间在{@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)}执行完之后执行 */ default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } 复制代码
afterCompletion
/** * 执行时间在{@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)}执行之前 */ default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } 复制代码
该组件主要有两个主要功能:
收集所有@RequestMapping
信息到注册表中
AbstractHandlerMethodMapping 实现了InitializingBean 接口,在初始化Servlet WebApplicationContext容器的时候初始化组件进行调用
调用getCandidateBeanNames
获取所有的Bean的名字
调用processCandidateBean
识别是处理器的Bean,同时搜集信息
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping public void afterPropertiesSet() { initHandlerMethods(); } //org.springframework.web.servlet.handler.AbstractHandlerMethodMapping protected void initHandlerMethods() { //getCandidateBeanNames 获取所有Bean名字 for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { //识别是处理器的Bean,同时进行搜集信息 processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } //org.springframework.web.servlet.handler.AbstractHandlerMethodMapping //获取所有Bean名字 protected String[] getCandidateBeanNames() { return (this.detectHandlerMethodsInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) : obtainApplicationContext().getBeanNamesForType(Object.class)); } 复制代码
调用AbstractHandlerMethodMapping的processCandidateBean
方法
isHandler
去除不是处理器的Bean,isHandler
是抽象方法,具体实现给子类,用于去除不是处理器的Bean//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping protected void processCandidateBean(String beanName) { Class<?> beanType = null; try { beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isTraceEnabled()) { logger.trace("Could not resolve type for bean '" + beanName + "'", ex); } } // 判断是否为处理器 if (beanType != null && isHandler(beanType)) { //搜集信息 detectHandlerMethods(beanName); } } 复制代码
调用detectHandlerMethods
方法进行搜集信息,注意入参其实是String类型的Bean的名字
如果是String类型,则通过Bean的名字获取Bean的Class类型
将Bean的方法和方法映射信息的T (比如@RequestMapping)信息做一个Map,getMappingForMethod
是抽象方法,给予子类实现
将这些方法和方法映射信息的T组册到注册表中
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping protected void detectHandlerMethods(Object handler) { //如果是String类型,则通过Bean的名字获取Bean的Class类型 Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { Class<?> userType = ClassUtils.getUserClass(handlerType); //将Bean的方法和方法映射信息的T (比如@RequestMapping)信息做一个Map Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } }); if (logger.isTraceEnabled()) { logger.trace(formatMappings(userType, methods)); } //将这些方法和方法映射信息的T组册到注册表中 methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } } 复制代码
调用registerHandlerMethod
方法进行将方法和方法映射信息T注册到注册表中
//org.springframework.web.servlet.handler.AbstractHandlerMethodMappin protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); } 复制代码
调用AbstractHandlerMethodMapping里面的内部类MappingRegistry的 register
方法将方法和方法映射信息T做一些map存储
构造HandlerMethod,也就是将处理器(Controller)和方法存储在一个对象,方便处理
验证是否一个映射信息只有一个方法对应
将映射信息T和方法做一个映射存储,框架可以根据映射信息和请求匹配合适的方法
获取所有没有特殊字符的存粹URL(比如没有/{userId}),将存粹URL和映射信息作一个LinkedHashMap,可以用于框架快速匹配
将命名信息和handlerMethod存储在ConcurrentHashMap
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry public void register(T mapping, Object handler, Method method) { // Assert that the handler method is not a suspending one. if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { Class<?>[] parameterTypes = method.getParameterTypes(); if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) { throw new IllegalStateException("Unsupported suspending handler method detected: " + method); } } this.readWriteLock.writeLock().lock(); try { //构造HandlerMethod,也就是将处理器(Controller)和方法存储在一个对象,方便处理 HandlerMethod handlerMethod = createHandlerMethod(handler, method); //验证是否一个映射信息只有一个方法对应 validateMethodMapping(handlerMethod, mapping); //将映射信息T和方法做一个映射存储 this.mappingLookup.put(mapping, handlerMethod); //获取所有没有特殊字符的存粹URL(比如没有/{userId}) List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { //将存粹URL和映射信息作一个LinkedHashMap this.urlLookup.add(url, mapping); } String name = null; if (getNamingStrategy() != null) { //通过命名策略对方法和映射信息进行命名 name = getNamingStrategy().getName(handlerMethod, mapping); //将命名信息和handlerMethod存储在ConcurrentHashMap addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } } 复制代码
调用createHandlerMethod
方法,将映射信息和方法存储在对象HandlerMethod
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping protected HandlerMethod createHandlerMethod(Object handler, Method method) { if (handler instanceof String) { return new HandlerMethod((String) handler, obtainApplicationContext().getAutowireCapableBeanFactory(), method); } return new HandlerMethod(handler, method); } 复制代码
调用validateMethodMapping
方法,验证一个映射信息是否只有一个方法对应
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping private void validateMethodMapping(HandlerMethod handlerMethod, T mapping) { // Assert that the supplied mapping is unique. HandlerMethod existingHandlerMethod = this.mappingLookup.get(mapping); if (existingHandlerMethod != null && !existingHandlerMethod.equals(handlerMethod)) { throw new IllegalStateException( "Ambiguous mapping. Cannot map '" + handlerMethod.getBean() + "' method \n" + handlerMethod + "\nto " + mapping + ": There is already '" + existingHandlerMethod.getBean() + "' bean method\n" + existingHandlerMethod + " mapped."); } } 复制代码
在AbstractHandlerMapping获取HandlerExecutionChain调用getHandlerInternal
获取处理器的复写
获取请求路径,存储在请求request作为缓存,给后面的查找请求路径快速定位
获取最合适的处理器和具体方法对象HandlerMethod
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //获取请求路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //存储在请求request作为缓存,给后面的查找请求路径快速定位 request.setAttribute(LOOKUP_PATH, lookupPath); this.mappingRegistry.acquireReadLock(); try { //获取最合适的处理器和具体方法对象HandlerMethod HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } } 复制代码
调用lookupHandlerMethod
获取最合适的处理器和具体方法对象HandlerMethod
存储匹配成功的映射信息和HandlerMethod,用于后面比较最合适的Match
从注册表中存粹路径和映射信息的map中获取
遍历映射信息,尝试获取匹配的映射信息,将信息存储在matches里面
如果还是没有找到则将所有的映射信息遍历,尝试获取匹配的映射信息,将信息存储在matches里面
如果匹配到超过1个Match,则需要比较出最合适的Match,通过比较映射信息匹配最合适的映射信息
如果比较出有两个合适的映射信息则报错,无法定位该使用哪个方法
处理映射信息
如果没有匹配成功则给出报错信息
//org.springframework.web.servlet.handler.AbstractHandlerMethodMap protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { // 存储匹配成功的映射信息和HandlerMethod,用于后面比较最合适的Match List<Match> matches = new ArrayList<>(); //从注册表中存粹路径和映射信息的map中获取 List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { //遍历映射信息,尝试获取匹配的映射信息,将信息存储在matches里面 addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... // 如果还是没有找到则将所有的映射信息遍历,尝试获取匹配的映射信息,将信息存储在matches里面 addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } if (!matches.isEmpty()) { Match bestMatch = matches.get(0); if (matches.size() > 1) { // 如果匹配到超过1个Match,则需要比较出最合适的Match,通过比较映射信息匹配最合适的映射信息 Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); matches.sort(comparator); bestMatch = matches.get(0); if (logger.isTraceEnabled()) { logger.trace(matches.size() + " matching mappings: " + matches); } if (CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } Match secondBestMatch = matches.get(1); // 如果比较出有两个合适的映射信息则报错,无法定位该使用哪个方法 if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); String uri = request.getRequestURI(); throw new IllegalStateException( "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}"); } } request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); //处理映射信息 handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { // 如果没有匹配成功则给出报错信息 return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } } 复制代码
调用addMatchingMappings
方法,尝试获取匹配的映射信息存储在Match
getMatchingMapping
尝试获取匹配的映射信息,如果匹配的话会生成新的映射信息,其中 getMatchingMapping
是抽象方法,给予子类实现//org.springframework.web.servlet.handler.AbstractHandlerMethodMap private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) { for (T mapping : mappings) { //尝试获取匹配的映射信息,如果匹配的话会生成新的映射信息 T match = getMatchingMapping(mapping, request); if (match != null) { //将匹配的映射信息和HandlerMethod存储在Match matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping))); } } } 复制代码
调用比较器进行排序,将最合适的放第一个,而比较的是映射信息
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MatchComparator private class MatchComparator implements Comparator<Match> { private final Comparator<T> comparator; public MatchComparator(Comparator<T> comparator) { this.comparator = comparator; } @Override public int compare(Match match1, Match match2) { //使用映射信息进行比较 return this.comparator.compare(match1.mapping, match2.mapping); } } 复制代码
调用handleMatch
方法处理匹配信息,该方法会被子类复写,将更多的信息存储在request里面
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) { request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath); } 复制代码
调用handleNoMatch
处理没有匹配方法情况,该方法被子类复写进行一些错误信息的处理
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpServletRequest request) throws Exception { return null; } 复制代码
RequestMappingInfoHandlerMapping 组件主要复写AbstractHandlerMethodMapping的getMatchingMapping
尝试获取映射信息和比较器getMappingComparator
和handleMatch
处理匹配信息和handleNoMatch
处理没有匹配映射信息
getMatchingMapping
用于尝试获取映射信息,该方法主要是映射信息的方法,在最后一个实现类进行解释
//org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) { return info.getMatchingCondition(request); } 复制代码
getMappingComparator
用于比较多个匹配成功的信息进行排序,该方法主要是映射信息的方法,在最后一个实现类进行解释
//org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping protected Comparator<RequestMappingInfo> getMappingComparator(final HttpServletRequest request) { return (info1, info2) -> info1.compareTo(info2, request); } 复制代码
handleMatch
方法将一些属性进行存储
//org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) { super.handleMatch(info, lookupPath, request); String bestPattern; Map<String, String> uriVariables; Set<String> patterns = info.getPatternsCondition().getPatterns(); if (patterns.isEmpty()) { bestPattern = lookupPath; uriVariables = Collections.emptyMap(); } else { bestPattern = patterns.iterator().next(); uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath); } request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern); if (isMatrixVariableContentAvailable()) { Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables); request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars); } Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables); request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables); if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) { Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes(); request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes); } } 复制代码
handleNoMatch
方法处理不匹配的情况说明
HttpMethod方法不匹配
Content-Type 不匹配
参数不匹配
//org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping protected HandlerMethod handleNoMatch( Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request) throws ServletException { PartialMatchHelper helper = new PartialMatchHelper(infos, request); if (helper.isEmpty()) { return null; } //HttpMethod方法不匹配 if (helper.hasMethodsMismatch()) { Set<String> methods = helper.getAllowedMethods(); if (HttpMethod.OPTIONS.matches(request.getMethod())) { HttpOptionsHandler handler = new HttpOptionsHandler(methods); return new HandlerMethod(handler, HTTP_OPTIONS_HANDLE_METHOD); } throw new HttpRequestMethodNotSupportedException(request.getMethod(), methods); } //Content-Type 不匹配 if (helper.hasConsumesMismatch()) { Set<MediaType> mediaTypes = helper.getConsumableMediaTypes(); MediaType contentType = null; if (StringUtils.hasLength(request.getContentType())) { try { contentType = MediaType.parseMediaType(request.getContentType()); } catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } } throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<>(mediaTypes)); } if (helper.hasProducesMismatch()) { Set<MediaType> mediaTypes = helper.getProducibleMediaTypes(); throw new HttpMediaTypeNotAcceptableException(new ArrayList<>(mediaTypes)); } //参数不匹配 if (helper.hasParamsMismatch()) { List<String[]> conditions = helper.getParamConditions(); throw new UnsatisfiedServletRequestParameterException(conditions, request.getParameterMap()); } return null; } 复制代码
该类就是我们一直在前面说的映射信息T,它的核心的功能有
combine
用于和另外一个映射信息进行合并getMatchingCondition
匹配合适的映射信息compareTo
比较两个映射信息,用来排序下面分别解释
用属性存储写在方法或者类上的@RequestMapping的信息
//org.springframework.web.servlet.mvc.method.RequestMappingInfo @Nullable private final String name; //路径匹配条件 private final PatternsRequestCondition patternsCondition; //Method方法匹配条件 private final RequestMethodsRequestCondition methodsCondition; //参数匹配条件 private final ParamsRequestCondition paramsCondition; //请求头匹配条件 private final HeadersRequestCondition headersCondition; private final ConsumesRequestCondition consumesCondition; private final ProducesRequestCondition producesCondition; //自定义的条件 private final RequestConditionHolder customConditionHolder; 复制代码
combine
将两个映射信息进行合并
//org.springframework.web.servlet.mvc.method.RequestMappingInfo public RequestMappingInfo combine(RequestMappingInfo other) { String name = combineNames(other); PatternsRequestCondition patterns = this.patternsCondition.combine(other.patternsCondition); RequestMethodsRequestCondition methods = this.methodsCondition.combine(other.methodsCondition); ParamsRequestCondition params = this.paramsCondition.combine(other.paramsCondition); HeadersRequestCondition headers = this.headersCondition.combine(other.headersCondition); ConsumesRequestCondition consumes = this.consumesCondition.combine(other.consumesCondition); ProducesRequestCondition produces = this.producesCondition.combine(other.producesCondition); RequestConditionHolder custom = this.customConditionHolder.combine(other.customConditionHolder); return new RequestMappingInfo(name, patterns, methods, params, headers, consumes, produces, custom.getCondition()); } 复制代码
getMatchingCondition
根据请求尝试获取匹配的映射信息,将映射信息里面的每一个条件进行匹配,如果其中一个方法没有匹配成功则返回null,如果有匹配成功的则最终将每一个新的条件作为属性生成新的映射信息
//org.springframework.web.servlet.mvc.method.RequestMappingInfo public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request); if (methods == null) { return null; } ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request); if (params == null) { return null; } HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request); if (headers == null) { return null; } ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request); if (consumes == null) { return null; } ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request); if (produces == null) { return null; } PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request); if (patterns == null) { return null; } RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request); if (custom == null) { return null; } return new RequestMappingInfo(this.name, patterns, methods, params, headers, consumes, produces, custom.getCondition()); } 复制代码
compareTo
比较两个映射信息,比较映射信息的每一个条件如果不相等则继续往下一个条件进行比较
//org.springframework.web.servlet.mvc.method.RequestMappingInfo public int compareTo(RequestMappingInfo other, HttpServletRequest request) { int result; // Automatic vs explicit HTTP HEAD mapping if (HttpMethod.HEAD.matches(request.getMethod())) { result = this.methodsCondition.compareTo(other.getMethodsCondition(), request); if (result != 0) { return result; } } result = this.patternsCondition.compareTo(other.getPatternsCondition(), request); if (result != 0) { return result; } result = this.paramsCondition.compareTo(other.getParamsCondition(), request); if (result != 0) { return result; } result = this.headersCondition.compareTo(other.getHeadersCondition(), request); if (result != 0) { return result; } result = this.consumesCondition.compareTo(other.getConsumesCondition(), request); if (result != 0) { return result; } result = this.producesCondition.compareTo(other.getProducesCondition(), request); if (result != 0) { return result; } // Implicit (no method) vs explicit HTTP method mappings result = this.methodsCondition.compareTo(other.getMethodsCondition(), request); if (result != 0) { return result; } result = this.customConditionHolder.compareTo(other.customConditionHolder, request); if (result != 0) { return result; } return 0; } 复制代码
RequestMappingHandlerMapping 实现类主要复写了AbstractHandlerMethodMapping的isHandler
用于判断Bean是否是处理器和复写AbstractHandlerMethodMapping的getMappingForMethod
用于构造映射信息
复写AbstractHandlerMethodMapping的isHandler
判断Bean是否是处理器,也就是判断是否有注解@Controller
和 @RequestMapping
标注
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping protected boolean isHandler(Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); } 复制代码
复写AbstractHandlerMethodMapping的getMappingForMethod
用于构造映射信息
调用createRequestMappingInfo
通过方法进行构造映射信息RequestMappingInfo
调用createRequestMappingInfo
通过处理器类型进行构造映射信息
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { //通过方法进行构造映射信息RequestMappingInfo RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { //通过处理器类型进行构造映射信息 RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { info = typeInfo.combine(info); } String prefix = getPathPrefix(handlerType); if (prefix != null) { info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info); } } return info; } 复制代码
调用createRequestMappingInfo
构造映射信息
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element)); //构造映射信息 return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null); } 复制代码
调用createRequestMappingInfo
构造映射信息
@RequestMapping
里面的信息使用RequestMappingInfo.Builder进行构造,方法简单不赘述//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping protected RequestMappingInfo createRequestMappingInfo( RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) { RequestMappingInfo.Builder builder = RequestMappingInfo .paths(resolveEmbeddedValuesInPatterns(requestMapping.path())) .methods(requestMapping.method()) .params(requestMapping.params()) .headers(requestMapping.headers()) .consumes(requestMapping.consumes()) .produces(requestMapping.produces()) .mappingName(requestMapping.name()); if (customCondition != null) { builder.customCondition(customCondition); } return builder.options(this.config).build(); } 复制代码
HandlerMapping组件的初始化我们在初始化Servlet WebApplicationContext里面没有细说,这次补上,主要分三种情况
handlerMapping
类型为HandlerMapping的BeanServlet WebApplicationContext容器初始化最后调用onRefresh
方法,再调用initStrategies
方法初始化全部组件,其中调用initHandlerMappings
初始化处理器映射器组件,从initHandlerMappings
这个方法开始解释
initHandlerMappings
方法,分三种情况,不赘述
//org.springframework.web.servlet.DispatcherServlet private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; //如果开启检测全部HandlerMapping的Bean则从已经注入的HandlerMapping的Bean进行初始化 if (this.detectAllHandlerMappings) { // 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<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { //如果不检测全部HandlerMapping的Bean,则根据HANDLER_MAPPING_BEAN_NAME获取 HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. //从配置文件获取默认的HandlerMapping全类名进行构造Bean初始化组件 if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isTraceEnabled()) { logger.trace("No HandlerMappings declared for servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties"); } } } 复制代码
调用getDefaultStrategies
方法
从默认配置获取处理器映射器的全类名,全类名有
通过反射获取Class类
根据Class类通过Servlet WebApplicationContext容器构建Bean进行初始化
//org.springframework.web.servlet.DispatcherServlet protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { String key = strategyInterface.getName(); //DispatcherServlet.properties获取默认配置为 // org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ //org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping String value = defaultStrategies.getProperty(key); if (value != null) { String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List<T> strategies = new ArrayList<>(classNames.length); for (String className : classNames) { try { //通过反射获取Class类 Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); //根据Class类通过Servlet WebApplicationContext容器构建Bean进行初始化 Object strategy = createDefaultStrategy(context, clazz); strategies.add((T) strategy); } catch (ClassNotFoundException ex) { throw new BeanInitializationException( "Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", ex); } catch (LinkageError err) { throw new BeanInitializationException( "Unresolvable class definition for DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", err); } } return strategies; } else { return new LinkedList<>(); } } 复制代码
defaultStrategies
属性的初始化
文件的位置DEFAULT_STRATEGIES_PATH = DispatcherServlet.properties
//org.springframework.web.servlet.DispatcherServlet private static final Properties defaultStrategies; static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { //文件的位置DEFAULT_STRATEGIES_PATH = DispatcherServlet.properties ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage()); } } 复制代码
调用createDefaultStrategy
通过类型进行构建Bean初始化处理器映射器组件
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) { return context.getAutowireCapableBeanFactory().createBean(clazz); } 复制代码