概述 右半边黄色的部分
注解 1 2 3 4 5 6 org.springframework.web.bind.annotation.@RequestMapping org.springframework.web.bind.annotation.@GetMapping org.springframework.web.bind.annotation.@PostMapping org.springframework.web.bind.annotation.@PutMapping org.springframework.web.bind.annotation.@DeleteMapping org.springframework.web.bind.annotation.@PatchMapping
AbstractHandlerMethodMapping 实现 InitializingBean 接口,继承 AbstractHandlerMapping 抽���类,以 Method 作为 Handler 的 HandlerMapping 抽象类,提供 Mapping 的初始化、注册等通用的骨架方法。这就是我们常说的“模板方法模式” 。
AbstractHandlerMethodMapping 定义为了 泛型,交给子类做决定。
例如,子类 RequestMappingInfoHandlerMapping 使用 RequestMappingInfo 类作为 泛型。
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // AbstractHandlerMethodMapping.java public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { /** * Mapping 注册表 */ private final MappingRegistry mappingRegistry = new MappingRegistry(); /** * Mapping 命名策略 */ @Nullable private HandlerMethodMappingNamingStrategy<T> namingStrategy; }
mappingRegistry 属性,Mapping 注册表
namingStrategy 属性,org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy 接口,Handler 的 Method 的 Mapping 的名字生成策略接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // HandlerMethodMappingNamingStrategy.java @FunctionalInterface public interface HandlerMethodMappingNamingStrategy<T> { /** * 获得名字 * * Determine the name for the given HandlerMethod and mapping. * @param handlerMethod the handler method * @param mapping the mapping * @return the name */ String getName(HandlerMethod handlerMethod, T mapping); }
我们就可以根据 Mapping 的名字,获得 Handler
该策略模式,只有一个实现策略。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // RequestMappingInfoHandlerMethodMappingNamingStrategy.java public class RequestMappingInfoHandlerMethodMappingNamingStrategy implements HandlerMethodMappingNamingStrategy<RequestMappingInfo> { /** Separator between the type and method-level parts of a HandlerMethod mapping name. */ public static final String SEPARATOR = "#"; @Override public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) { // 情况一,mapping 名字非空,则使用 mapping 的名字 if (mapping.getName() != null) { return mapping.getName(); } // 情况二,使用类名大写 + "#" + 方法名 StringBuilder sb = new StringBuilder(); String simpleTypeName = handlerMethod.getBeanType().getSimpleName(); for (int i = 0 ; i < simpleTypeName.length(); i++) { if (Character.isUpperCase(simpleTypeName.charAt(i))) { sb.append(simpleTypeName.charAt(i)); } } sb.append(SEPARATOR).append(handlerMethod.getMethod().getName()); return sb.toString(); } }
MappingRegistry MappingRegistry ,是 AbstractHandlerMethodMapping 的私有类,Mapping 注册表。
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 // AbstractHandlerMethodMapping.java#MappingRegistry /** * 注册表 * * KEY: Mapping */ private final Map<T, MappingRegistration<T>> registry = new HashMap<>(); /** * 注册表2 * * KEY:Mapping */ private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>(); /** * 直接 URL 的映射 * * KEY:直接 URL * VALUE:Mapping 数组 */ private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>(); /** * Mapping 的名字与 HandlerMethod 的映射 * * KEY:Mapping 的名字 * VALUE:HandlerMethod 数组 */ private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>(); /** * TODO 1012 cors */ private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>(); /** * 读写锁 */ private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
读写锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /** * 获得读锁 * * Acquire the read lock when using getMappings and getMappingsByUrl. */ public void acquireReadLock() { this.readWriteLock.readLock().lock(); } /** * 获得写锁 * * Release the read lock after using getMappings and getMappingsByUrl. */ public void releaseReadLock() { this.readWriteLock.readLock().unlock(); }
register register(T mapping, Object handler, Method method) 方法,注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 // AbstractHandlerMethodMapping.java#MappingRegistry public void register(T mapping, Object handler, Method method) { // <1> 获得写锁 this.readWriteLock.writeLock().lock(); try { // <2.1> 创建 HandlerMethod 对象 HandlerMethod handlerMethod = createHandlerMethod(handler, method); // <2.2> 校验当前 mapping 不存在,否则抛出 IllegalStateException 异常 assertUniqueMethodMapping(handlerMethod, mapping); // <2.3> 添加 mapping + HandlerMethod 到 mappingLookup 中 this.mappingLookup.put(mapping, handlerMethod); // <3.1> 获得 mapping 对应的普通 URL 数组 List<String> directUrls = getDirectUrls(mapping); // <3.2> 添加到 url + mapping 到 urlLookup 集合中 for (String url : directUrls) { this.urlLookup.add(url, mapping); } // <4> 初始化 nameLookup String name = null; if (getNamingStrategy() != null) { // <4.1> 获得 Mapping 的名字 name = getNamingStrategy().getName(handlerMethod, mapping); // <4.2> 添加到 mapping 的名字 + HandlerMethod 到 nameLookup 中 addMappingName(name, handlerMethod); } // <5> TODO 1012 cors CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } // <6> 创建 MappingRegistration 对象,并 mapping + MappingRegistration 添加到 registry 中 this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod)); } finally { // <7> 释放写锁 this.readWriteLock.writeLock().unlock(); } }
校验不存在,抛出异常
1 2 3 4 5 6 7 8 9 10 11 // AbstractHandlerMethodMapping.java#MappingRegistry private void assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping) { HandlerMethod handlerMethod = this.mappingLookup.get(mapping); if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) { // 存在,且不相等,说明不唯一 throw new IllegalStateException( "Ambiguous mapping. Cannot map '" + newHandlerMethod.getBean() + "' method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" + handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped."); } }
调用 #getDirectUrls(T mapping) 方法,获得 mapping 对应的直接 URL 数组
1 2 3 4 5 6 7 8 9 10 11 12 13 // AbstractHandlerMethodMapping.java#MappingRegistry private List<String> getDirectUrls(T mapping) { List<String> urls = new ArrayList<>(1); // 遍历 Mapping 对应的路径 for (String path : getMappingPathPatterns(mapping)) { // 非**模式**路径 if (!getPathMatcher().isPattern(path)) { urls.add(path); } } return urls; }
例如,@RequestMapping(“/user/login”) 注解对应的路径,就是直接路径
例如,@RequestMapping(“/user/${id}”) 注解对应的路径,不是直接路径
调用 #addMappingName(String name, HandlerMethod handlerMethod) 方法,添加 mapping 的名字 + HandlerMethod 到 nameLookup 中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // AbstractHandlerMethodMapping.java#MappingRegistry private void addMappingName(String name, HandlerMethod handlerMethod) { // 获得 Mapping 的名字,对应的 HandlerMethod 数组 List<HandlerMethod> oldList = this.nameLookup.get(name); if (oldList == null) { oldList = Collections.emptyList(); } // 如果已经存在,则不用添加 for (HandlerMethod current : oldList) { if (handlerMethod.equals(current)) { return; } } // 添加到 nameLookup 中 List<HandlerMethod> newList = new ArrayList<>(oldList.size() + 1); // 重新创建的原因是,保证数组的大小固定。因为,基本不太存在扩容的可能性,申请大了就浪费了。 newList.addAll(oldList); newList.add(handlerMethod); this.nameLookup.put(name, newList); }
unregister unregister(T mapping) 方法,取消注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 // AbstractHandlerMethodMapping.java#MappingRegistry public void unregister(T mapping) { // 获得写锁 this.readWriteLock.writeLock().lock(); try { // 从 registry 中移除 MappingRegistration<T> definition = this.registry.remove(mapping); if (definition == null) { return; } // 从 mappingLookup 中移除 this.mappingLookup.remove(definition.getMapping()); // 从 urlLookup 移除 for (String url : definition.getDirectUrls()) { List<T> list = this.urlLookup.get(url); if (list != null) { list.remove(definition.getMapping()); if (list.isEmpty()) { this.urlLookup.remove(url); } } } // 从 nameLookup 移除 removeMappingName(definition); // 从 corsLookup 中移除 this.corsLookup.remove(definition.getHandlerMethod()); } finally { // 释放写锁 this.readWriteLock.writeLock().unlock(); } }
createHandlerMethod 创建 HandlerMethod 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // AbstractHandlerMethodMapping.java protected HandlerMethod createHandlerMethod(Object handler, Method method) { HandlerMethod handlerMethod; // <1> 如果 handler 类型为 String, 说明对应一个 Bean 对象,例如 UserController 使用 @Controller 注解后,默认 handler 为它的 beanName ,即 `userController` if (handler instanceof String) { String beanName = (String) handler; handlerMethod = new HandlerMethod(beanName, obtainApplicationContext().getAutowireCapableBeanFactory(), method); // <2> 如果 handler 类型非 String ,说明是一个已经是一个 handler 对象,就无需处理,直接创建 HandlerMethod 对象 } else { handlerMethod = new HandlerMethod(handler, method); } return handlerMethod; }
我们已经可以觉察,实际上,HandlerMethod 是 handler + method 的组合,一个对象的某个方法。
HandlerMethod 处理器的方法的封装对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 // HandlerMethod.java /** * Bean 对象 */ private final Object bean; @Nullable private final BeanFactory beanFactory; /** * Bean 的类型 */ private final Class<?> beanType; /** * 方法 */ private final Method method; /** * {@link #method} 的桥接方法 * * 详细说明 * * 1. https://www.jianshu.com/p/250030ea9b28 * 2. https://blog.csdn.net/mhmyqn/article/details/47342577 */ private final Method bridgedMethod; /** * 方法参数数组 */ private final MethodParameter[] parameters; /** * 响应的状态码,即 {@link ResponseStatus#code()} */ @Nullable private HttpStatus responseStatus; /** * 响应的状态码原因,即 {@link ResponseStatus#reason()} */ @Nullable private String responseStatusReason; /** * 解析自哪个 HandlerMethod 对象 * * 仅构造方法中传入 HandlerMethod 类型的参数适用,例如 {@link #HandlerMethod(HandlerMethod)} */ @Nullable private HandlerMethod resolvedFromHandlerMethod; /** * 父接口的方法的参数注解数组 */ @Nullable private volatile List<Annotation[][]> interfaceParameterAnnotations;
构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // HandlerMethod.java /** * Create an instance from a bean name, a method, and a {@code BeanFactory}. * The method {@link #createWithResolvedBean()} may be used later to * re-create the {@code HandlerMethod} with an initialized bean. */ public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) { Assert.hasText(beanName, "Bean name is required"); Assert.notNull(beanFactory, "BeanFactory is required"); Assert.notNull(method, "Method is required"); // <1> 将 beanName 赋值给 bean 属性,说明 beanFactory + bean 的方式,获得 handler 对象 this.bean = beanName; this.beanFactory = beanFactory; // <2> 初始化 beanType 属性 Class<?> beanType = beanFactory.getType(beanName); if (beanType == null) { throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'"); } this.beanType = ClassUtils.getUserClass(beanType); // <3> 初始化 method、bridgedMethod 属性 this.method = method; this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); // <4> 初始化 parameters 属性 this.parameters = initMethodParameters(); // <5> 初始化 responseStatus、responseStatusReason 属性 evaluateResponseStatus(); }
evaluateResponseStatus() 方法,初始化 responseStatus、responseStatusReason 属性。
1 2 3 4 5 6 7 8 9 10 11 12 // HandlerMethod.java private void evaluateResponseStatus() { ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class); if (annotation == null) { annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class); } if (annotation != null) { this.responseStatus = annotation.code(); this.responseStatusReason = annotation.reason(); } }
调用 #initMethodParameters() 方法,初始化 parameters 属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 // HandlerMethod.java private MethodParameter[] initMethodParameters() { int count = this.bridgedMethod.getParameterCount(); // 创建 MethodParameter 数组 MethodParameter[] result = new MethodParameter[count]; // 遍历 bridgedMethod 的参数,逐个解析参数类型 for (int i = 0; i < count; i++) { HandlerMethodParameter parameter = new HandlerMethodParameter(i); GenericTypeResolver.resolveParameterType(parameter, this.beanType); result[i] = parameter; } return result; }
MappingRegistration MappingRegistration ,是 AbstractHandlerMethodMapping 的私有静态类,Mapping 注册登记。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 // AbstractHandlerMethodMapping.java private static class MappingRegistration<T> { /** * Mapping 对象 */ private final T mapping; /** * HandlerMethod 对象 */ private final HandlerMethod handlerMethod; /** * 直接 URL 数组 */ private final List<String> directUrls; /** * {@link #mapping} 的名字 */ @Nullable private final String mappingName; public MappingRegistration(T mapping, HandlerMethod handlerMethod, @Nullable List<String> directUrls, @Nullable String mappingName) { Assert.notNull(mapping, "Mapping must not be null"); Assert.notNull(handlerMethod, "HandlerMethod must not be null"); this.mapping = mapping; this.handlerMethod = handlerMethod; this.directUrls = (directUrls != null ? directUrls : Collections.emptyList()); this.mappingName = mappingName; } // ... 省略 getting 方法 }
afterPropertiesSet 实现 #afterPropertiesSet() 方法,进行初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // AbstractHandlerMethodMapping.java /** * 是否只扫描可访问的 HandlerMethod 们 */ private boolean detectHandlerMethodsInAncestorContexts = false; @Override public void afterPropertiesSet() { // <x> 初始化处理器的方法们 initHandlerMethods(); } /** * Scan beans in the ApplicationContext, detect and register handler methods. * @see #getCandidateBeanNames() * @see #processCandidateBean * @see #handlerMethodsInitialized */ protected void initHandlerMethods() { // <1.1> 遍历 Bean ,逐个处理 for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { // <1.2> 处理 Bean processCandidateBean(beanName); } } // <2> 初始化处理器的方法们。目前是空方法,暂无具体的实现 handlerMethodsInitialized(getHandlerMethods()); }
调用 #getCandidateBeanNames() 方法,获得所有 Bean 的名字们,然后进行遍历处理
1 2 3 4 5 6 7 8 9 10 11 12 13 // AbstractHandlerMethodMapping.java /** * Determine the names of candidate beans in the application context. * @since 5.1 * @see #setDetectHandlerMethodsInAncestorContexts * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors */ protected String[] getCandidateBeanNames() { return (this.detectHandlerMethodsInAncestorContexts ? // 可访问 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) : obtainApplicationContext().getBeanNamesForType(Object.class)); }
processCandidateBean 判断 Bean 是否为处理器,如果是,则扫描处理器方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // AbstractHandlerMethodMapping.java /** * Determine the type of the specified candidate bean and call * {@link #detectHandlerMethods} if identified as a handler type. * <p>This implementation avoids bean creation through checking * {@link org.springframework.beans.factory.BeanFactory#getType} * and calling {@link #detectHandlerMethods} with the bean name. * @param beanName the name of the candidate bean * @since 5.1 * @see #isHandler * @see #detectHandlerMethods */ protected void processCandidateBean(String beanName) { // <1> 获得 Bean 对应的类型 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); } } // 判断 Bean 是否为处理器,如果是,则扫描处理器方法 if (beanType != null && isHandler(beanType)) { // <2.1> detectHandlerMethods(beanName); // <2.2> } }
detectHandlerMethods(Object handler) 方法, 扫描处理器的方法们
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // AbstractHandlerMethodMapping.java /** * Look for handler methods in a handler. * @param handler the bean name of a handler or a handler instance */ protected void detectHandlerMethods(final Object handler) { // <1> 获得处理器类型 Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { // <2> 获得真实的类。因为,handlerType 可能是代理类 final Class<?> userType = ClassUtils.getUserClass(handlerType); // <3> 获得匹配的方法的集合 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType)); // 抽象方法,子类实现 if (logger.isTraceEnabled()) { logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods); } // <4> 遍历方法,逐个注册 HandlerMethod methods.forEach((key, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(key, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } }
ClassUtils#getUserClass(handlerType) 方法,获得真实的类。因为,handlerType 可能是代理类。
1 2 3 4 5 6 7 8 9 10 11 12 // ClassUtils.java public static Class<?> getUserClass(Class<?> clazz) { // 如果 CG_CLASS 代理类,则获取其父类 if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { Class<?> superclass = clazz.getSuperclass(); if (superclass != null && superclass != Object.class) { return superclass; } } return clazz; }
获得匹配的方法的集合。通过 #getMappingForMethod(Method method, Class<?> handlerType) 抽象方法,获得方法的 Mapping 信息。
1 2 @Nullable protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
该方法在 RequestMappingHandlerMapping 类中实现。
逐个调用 #registerHandlerMethod(Object handler, Method method, T mapping) 方法,注册 HandlerMethod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // AbstractHandlerMethodMapping.java /** * 注册 HandlerMethod * * Register a handler method and its unique mapping. Invoked at startup for * each detected handler method. * @param handler the bean name of the handler or the handler instance * @param method the method to register * @param mapping the mapping conditions associated with the handler method * @throws IllegalStateException if another method was already registered * under the same mapping */ protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); }
这样,Mapping 和 handler + method ,就成功注册到 mappingRegistry 中。究竟 Mapping 是什么?实际上,在 RequestMappingHandlerMapping 中,就是 @RequestMapping 解析成的 RequestMappingInfo 对象。
getHandlerInternal 获得请求对应的 HandlerMethod 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // AbstractHandlerMethodMapping.java // AbstractHandlerMethodMapping.java /** * Look up a handler method for the given request. */ @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // <1> 获得请求的路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // <2> 获得写锁 this.mappingRegistry.acquireReadLock(); try { // <3> 获得 HandlerMethod 对象 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); // <4> 进一步,获得 HandlerMethod 对象 return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { // <5> 释放写锁 this.mappingRegistry.releaseReadLock(); } }
调用 #lookupHandlerMethod(ServerWebExchange exchange) 方法,获得 HandlerMethod 对象
如果获得到 HandlerMethod 对象,则调用 HandlerMethod#createWithResolvedBean() 方法,进一步,获得 HandlerMethod 对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // HandlerMethod.java /** * If the provided instance contains a bean name rather than an object instance, * the bean name is resolved before a {@link HandlerMethod} is created and returned. */ public HandlerMethod createWithResolvedBean() { Object handler = this.bean; // 如果是 bean 是 String类型,则获取对应的 handler 对象。例如,bean = userController 字符串,获取后,handler = UserController 对象 if (this.bean instanceof String) { Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory"); String beanName = (String) this.bean; handler = this.beanFactory.getBean(beanName); } // 创建 HandlerMethod 对象 return new HandlerMethod(this, handler); }
lookupHandlerMethod 获得 HandlerMethod 对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { // <1> Match 数组,存储匹配上当前请求的结果 List<Match> matches = new ArrayList<>(); // <1.1> 优先,基于直接 URL 的 Mapping 们,进行匹配 List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } // <1.2> 其次,扫描注册表的 Mapping 们,进行匹配 if (matches.isEmpty()) { // No choice but to go through all mappings... addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } // <2> 如果匹配到,则获取最佳匹配的 Match 对象的 handlerMethod 属性 if (!matches.isEmpty()) { // <2.1> 创建 MatchComparator 对象,排序 matches 结果 Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); matches.sort(comparator); // <2.2> 获得首个 Match 对象 Match bestMatch = matches.get(0); // <2.3> 处理存在多个 Match 对象的情况!! if (matches.size() > 1) { if (logger.isTraceEnabled()) { logger.trace(matches.size() + " matching mappings: " + matches); } // TODO 1012 cors if (CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } // 比较 bestMatch 和 secondBestMatch ,如果相等,说明有问题,抛出 IllegalStateException 异常 // 因为,两个优先级一样高,说明无法判断谁更优先 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 + "}"); } } // <2.4> 处理首个 Match 对象 handleMatch(bestMatch.mapping, lookupPath, request); // <2.5> 返回首个 Match 对象的 handlerMethod 属性 return bestMatch.handlerMethod; // <3> 如果匹配不到,则处理不匹配的情况 } else { return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } }
优先,基于直接 URL 的 Mapping 们,进行匹配
其次,基于扫描注册表的 Mapping 们,进行匹配
Match 数组,存储匹配上当前请求的结果。Match 是 AbstractHandlerMethodMapping 的内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private class Match { /** * Mapping 对象 */ private final T mapping; /** * HandlerMethod 对象 */ private final HandlerMethod handlerMethod; public Match(T mapping, HandlerMethod handlerMethod) { this.mapping = mapping; this.handlerMethod = handlerMethod; } @Override public String toString() { return this.mapping.toString(); } }
addMatchingMappings(Collection mappings, List matches, ServerWebExchange exchange) 方法,将当前请求和注册表中的 Mapping 进行匹配。若匹配成功,则生成 Mapping 记录,添加到 matches 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 // AbstractHandlerMethodMapping.java private void addMatchingMappings(Collection<T> mappings, List<Match> matches, ServerWebExchange exchange) { // 遍历 Mapping 数组 for (T mapping : mappings) { // <1> 执行匹配 T match = getMatchingMapping(mapping, exchange); // <2> 如果匹配,则创建 Match 对象,添加到 matches 中 if (match != null) { matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping))); } } }
遍历 Mapping 数组,逐个调用 #getMatchingMapping(T mapping, ServerWebExchange exchange) 抽象方法,执行匹配。
如果匹配,则返回的结果非空。则创建 Match 对象,添加到 matches 中
创建 MatchComparator 对象,排序 matches 结果。其中 MatchComparator 实现 Comparator 接口,是 AbstractHandlerMethodMapping 的私有类,Match 排序器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // AbstractHandlerMethodMapping.java 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); } }
获得首个 Match 对象 bestMatch 变量
处理存在多个 Match 对象的情况!!获得第二 Match 对象 secondBestMatch 变量。通过 bestMatch 和 secondBestMatch 的比较,如果一样的优先级,则抛出 IllegalStateException 异常。因为,两个优先级一样高,说明无法判断谁更优先。
调用 #handleMatch(T mapping, String lookupPath, HttpServletRequest request) 方法,设置匹配的路径 lookupPath 到请求属性种。
1 2 3 4 5 // AbstractHandlerMethodMapping.java protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) { request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath); }
如果匹配不到,调用 #handleNoMatch(Set mappings, String lookupPath, HttpServletRequest request) 方法,处理不匹配的情况。
1 2 3 4 5 @Nullable protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpServletRequest request) throws Exception { return null; }
RequestMappingInfoHandlerMapping org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping ,继承 AbstractHandlerMethodMapping 抽象类,定义了使用的泛型 为 org.springframework.web.servlet.mvc.method.RequestMappingInfo 类,即 ==Mapping 类型就是 RequestMappingInfo ==
好处 RequestMappingInfoHandlerMapping 定义了使用了 RequestMappingInfo 对象,而 其子类 RequestMappingHandlerMapping 使用了 @RequestMapping 注解,来生成 RequestMappingInfo 对象。
这样,如果未来我们自己定义了自己的注解,或者其他方式来生成 RequestMappingHandlerMapping 对象,未尝不可。
构造方法 1 2 3 4 5 6 7 8 9 // RequestMappingInfoHandlerMapping.java public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> { protected RequestMappingInfoHandlerMapping() { setHandlerMethodMappingNamingStrategy(new RequestMappingInfoHandlerMethodMappingNamingStrategy()); } }
泛型,为 RequestMappingInfo 类型
设置了 AbstractHandlerMethodMapping.namingStrategy 属性,为 RequestMappingInfoHandlerMethodMappingNamingStrategy 对象。
RequestMappingInfo
RequestMappingInfo 不是 RequestMappingInfoHandlerMapping 的内部类,但是是 RequestMappingInfo-HandlerMapping 的前缀。
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 // RequestMappingInfo.java /** * 名字 */ @Nullable private final String name; /** * 请求路径的条件 */ private final PatternsRequestCondition patternsCondition; /** * 请求方法的条件 */ private final RequestMethodsRequestCondition methodsCondition; /** * 参数的条件 */ private final ParamsRequestCondition paramsCondition; /** * 请求头的条件 */ private final HeadersRequestCondition headersCondition; /** * 可消费的 Content-Type 的条件 */ private final ConsumesRequestCondition consumesCondition; /** * 可生产的 Content-Type 的条件 */ private final ProducesRequestCondition producesCondition; /** * 自定义的条件 */ private final RequestConditionHolder customConditionHolder;
我们可以看到各种条件。实际上,和 @RequestMapping 注解是一一对应的。
日常使用最多的还是 patternsCondition 请求路径条件,和 methodsCondition 请求方法条件。
getMatchingCondition 从当前 RequestMappingInfo 获得匹配的条件。如果匹配,则基于其匹配的条件,创建新的 RequestMappingInfo 对象。如果不匹配,则返回 null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 // RequestMappingInfo.java @SuppressWarnings("Duplicates") @Override @Nullable public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { // 匹配 methodsCondition、paramsCondition、headersCondition、consumesCondition、producesCondition RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request); ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request); HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request); ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request); ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request); // 如果任一为空,则返回 null ,表示匹配失败 if (methods == null || params == null || headers == null || consumes == null || produces == null) { return null; } // 匹配 patternsCondition PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request); if (patterns == null) { // 如果 patterns 为空,则返回 null ,表示匹配失败 return null; } // 匹配 customConditionHolder RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request); if (custom == null) { // 如果 custom 为空,则返回 null ,表示匹配失败 return null; } // 创建匹配的 RequestMappingInfo 对象。 // 为什么要创建 RequestMappingInfo 对象呢?因为当前 RequestMappingInfo 对象,一个 methodsCondition 可以配置 GET、POST、DELETE 等等条件,但是实际就匹配一个请求类型,此时 methods 只代表其匹配的那个。 return new RequestMappingInfo(this.name, patterns, methods, params, headers, consumes, produces, custom.getCondition()); }
实际都是调用每个属性对应的 #getMatchingCondition(HttpServletRequest request) 方法,获得其匹配的真正的条件。
如果一个 @RequestMapping(value = “user/login”) 注解,并未写 RequestMethod 的条件,岂不是会报空?实际上不会。在这种情况下,会创建一个 RequestMethodsRequestCondition 对象,并且在匹配时,直接返回自身。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private final Set<RequestMethod> methods; @Override @Nullable public RequestMethodsRequestCondition getMatchingCondition(HttpServletRequest request) { if (CorsUtils.isPreFlightRequest(request)) { return matchPreFlight(request); } // 空的情况下,就返回自身 if (getMethods().isEmpty()) { if (RequestMethod.OPTIONS.name().equals(request.getMethod()) && !DispatcherType.ERROR.equals(request.getDispatcherType())) { return null; // No implicit match for OPTIONS (we handle it) } return this; } // 非空,逐个匹配 return matchRequestMethod(request.getMethod()); }
compareTo 比较优先级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Override public int compareTo(RequestMappingInfo other, HttpServletRequest request) { int result; // Automatic vs explicit HTTP HEAD mapping // 针对 HEAD 请求方法,特殊处理 if (HttpMethod.HEAD.matches(request.getMethod())) { result = this.methodsCondition.compareTo(other.getMethodsCondition(), request); if (result != 0) { return result; } } // 比较 patternsCondition result = this.patternsCondition.compareTo(other.getPatternsCondition(), request); if (result != 0) { return result; } // 比较 paramsCondition result = this.paramsCondition.compareTo(other.getParamsCondition(), request); if (result != 0) { return result; } // 比较 headersCondition result = this.headersCondition.compareTo(other.getHeadersCondition(), request); if (result != 0) { return result; } // 比较 consumesCondition result = this.consumesCondition.compareTo(other.getConsumesCondition(), request); if (result != 0) { return result; } // 比较 producesCondition result = this.producesCondition.compareTo(other.getProducesCondition(), request); if (result != 0) { return result; } // Implicit (no method) vs explicit HTTP method mappings // 比较 methodsCondition result = this.methodsCondition.compareTo(other.getMethodsCondition(), request); if (result != 0) { return result; } // 比较 customConditionHolder result = this.customConditionHolder.compareTo(other.customConditionHolder, request); if (result != 0) { return result; } return 0; }
PatternsRequestCondition 继承 AbstractRequestCondition 抽象类,请求路径条件。https://www.cnblogs.com/fangjian0423/p/springMVC-request-mapping.html
getMappingPathPatterns 获得 Mapping 对应的请求路径集合
1 2 3 4 @Override protected Set<String> getMappingPathPatterns(RequestMappingInfo info) { return info.getPatternsCondition().getPatterns(); }
getMatchingMapping 1 2 3 4 @Override protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) { return info.getMatchingCondition(request); }
handleMatch 覆写父类的方法,设置更多的属性,到请求中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Override protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) { super.handleMatch(info, lookupPath, request); // 获得 bestPattern 和 uriVariables 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); // 设置 MATRIX_VARIABLES_ATTRIBUTE 属性,到请求中 if (isMatrixVariableContentAvailable()) { Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables); request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars); } // 设置 URI_TEMPLATE_VARIABLES_ATTRIBUTE 属性,到请求中 Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables); request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables); // 设置 PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE 属性,到请求中 if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) { Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes(); request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes); } }
handleNoMatch 覆写父类方法,处理无匹配 Mapping 的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @Override protected HandlerMethod handleNoMatch( Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request) throws ServletException { // <1> 创建 PartialMatchHelper 对象,解析可能的错误 PartialMatchHelper helper = new PartialMatchHelper(infos, request); if (helper.isEmpty()) { return null; } // <2> 方法错误 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)); } // 可生产的 Content-Type 错误 if (helper.hasProducesMismatch()) { Set<MediaType> mediaTypes = helper.getProducibleMediaTypes(); throw new HttpMediaTypeNotAcceptableException(new ArrayList<>(mediaTypes)); } // <5> 参数错误 if (helper.hasParamsMismatch()) { List<String[]> conditions = helper.getParamConditions(); throw new UnsatisfiedServletRequestParameterException(conditions, request.getParameterMap()); } return null; }
核心代码在 PartialMatchHelper 中实现
RequestMappingHandlerMapping 实现 MatchableHandlerMapping 接口、EmbeddedValueResolverAware 接口,继承 RequestMappingInfoHandlerMapping 抽象类,基于 @RequestMapping 注解来构建 RequestMappingInfo 对象。
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // RequestMappingHandlerMapping.java private boolean useSuffixPatternMatch = true; private boolean useRegisteredSuffixPatternMatch = false; private boolean useTrailingSlashMatch = true; private Map<String, Predicate<Class<?>>> pathPrefixes = new LinkedHashMap<>(); private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); @Nullable private StringValueResolver embeddedValueResolver; /** * RequestMappingInfo.BuilderConfiguration 配置 */ private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration();
afterPropertiesSet 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // RequestMappingHandlerMapping.java @Override public void afterPropertiesSet() { // 构建 RequestMappingInfo.BuilderConfiguration 对象 this.config = new RequestMappingInfo.BuilderConfiguration(); this.config.setUrlPathHelper(getUrlPathHelper()); this.config.setPathMatcher(getPathMatcher()); this.config.setSuffixPatternMatch(this.useSuffixPatternMatch); this.config.setTrailingSlashMatch(this.useTrailingSlashMatch); this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch); this.config.setContentNegotiationManager(getContentNegotiationManager()); // 调用父类,初始化 super.afterPropertiesSet(); }
isHandler 判断是否为处理器
1 2 3 4 5 @Override protected boolean isHandler(Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }
获得方法上的 RequestMappingInfo 对象,基于 @RequestMapping 构造。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Override @Nullable protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { // <1> 基于方法上的 @RequestMapping 注解,创建 RequestMappingInfo 对象 RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { // <2> 基于类上的 @RequestMapping 注解,合并进去 RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { info = typeInfo.combine(info); } // <3> 如果有前缀,则设置到 info 中 String prefix = getPathPrefix(handlerType); if (prefix != null) { info = RequestMappingInfo.paths(prefix).build().combine(info); } } return info; }
createRequestMappingInfo
1 2 3 4 5 6 7 8 9 10 @Nullable private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { // <1> 获得 @RequestMapping 注解 RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); // <2> 获得自定义的条件。目前都是空方法,可以无视 RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element)); // <3> 基于 @RequestMapping 注解,创建 RequestMappingInfo 对象 return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null); }
createRequestMappingInfo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) { // 创建 RequestMappingInfo.Builder 对象,设置对应属性 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); } // 创建 RequestMappingInfo 对象 return builder.options(this.config).build(); }
基于类上的 @RequestMapping 注解,创建 RequestMappingInfo 对象,并合并进去。
match 执行匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override public RequestMatchResult match(HttpServletRequest request, String pattern) { // 创建 RequestMappingInfo 对象 RequestMappingInfo info = RequestMappingInfo.paths(pattern).options(this.config).build(); // 获得匹配的 RequestMappingInfo 对象 RequestMappingInfo matchingInfo = info.getMatchingCondition(request); if (matchingInfo == null) { // 如果不匹配,则返回 null return null; } // 获得请求路径的集合 Set<String> patterns = matchingInfo.getPatternsCondition().getPatterns(); // 获得请求的路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // 创建 RequestMatchResult 结果 return new RequestMatchResult(patterns.iterator().next(), lookupPath, getPathMatcher()); }