该系列文档是本人在学习 Spring MVC 的源码过程当中总结下来的,可能对读者不太友好,请结合个人源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读html
Spring 版本:5.2.4.RELEASEjava
该系列其余文档请查看:《精尽 Spring MVC 源码分析 - 文章导读》git
HandlerMapping 组件,请求的处理器匹配器,负责为请求找到合适的 HandlerExecutionChain
处理器执行链,包含处理器(handler
)和拦截器们(interceptors
)github
handler
处理器是 Object 类型,能够将其理解成 HandlerMethod 对象(例如咱们使用最多的 @RequestMapping
注解所标注的方法会解析成该对象),包含了方法的全部信息,经过该对象可以执行该方法web
HandlerInterceptor
拦截器对处理请求进行加强处理,可用于在执行方法前、成功执行方法后、处理完成后进行一些逻辑处理spring
因为 HandlerMapping 组件涉及到的内容比较多,考虑到内容的排版,因此将这部份内容拆分红了四个模块,依次进行分析:api
先来回顾一下HandlerMapping 接口体系的结构:数组
在《HandlerMapping 组件(一)之 AbstractHandlerMapping》文档中已经分析了 HandlerMapping 组件的 AbstractHandlerMapping 抽象类基类安全
那么本文就接着来分析图中红色框部分的 AbstractHandlerMethodMapping 系,该系是基于 Method 进行匹配。例如,咱们所熟知的 @RequestMapping
等注解的方式。一共就三个类,很少😈😈😈mvc
涉及到的内容比较多,能够直接查看个人总结
先来回顾一下在 DispatcherServlet
中处理请求的过程当中经过 HandlerMapping 组件,获取到 HandlerExecutionChain 处理器执行链的方法,是经过AbstractHandlerMapping 的 getHandler 方法来获取的,以下:
@Override @Nullable public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // <1> 得到处理器(HandlerMethod 或者 HandlerExecutionChain),该方法是抽象方法,由子类实现 Object handler = getHandlerInternal(request); // <2> 得到不到,则使用默认处理器 // <3> 仍是得到不到,则返回 null // <4> 若是找到的处理器是 String 类型,则从 Spring 容器中找到对应的 Bean 做为处理器 // <5> 建立 HandlerExecutionChain 对象(包含处理器和拦截器) // ... 省略相关代码 return executionChain; }
在 AbstractHandlerMapping 获取 HandlerExecutionChain 处理器执行链的方法中,须要先调用 getHandlerInternal(HttpServletRequest request)
抽象方法,获取请求对应的处理器,该方法由子类去实现,也就上图中黄色框和红色框两类子类,本文分析红色框部份内容
Spring MVC 的请求匹配的注解,体系结构以下:
关于这些注解,你们已经很是熟悉了,各自的属性就再也不进行讲述了,可具体查看源码:
org.springframework.web.servlet.result.method.AbstractHandlerMethodMapping
,实现 InitializingBean 接口,继承 AbstractHandlerMapping 抽象类,以 Method 方法 做为 Handler 处理器 的 HandlerMapping 抽象类,提供 Mapping 的初始化、注册等通用的骨架方法。
那么具体是什么呢?AbstractHandlerMethodMapping 定义为了 <T>
泛型,交给子类作决定。例如,子类 RequestMappingInfoHandlerMapping 使用 RequestMappingInfo 类做为 <T>
泛型,也就是咱们在上面注解模块看到的 @RequestMapping
等注解信息。
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { /** * 是否只扫描可访问的 HandlerMethod 们 */ private boolean detectHandlerMethodsInAncestorContexts = false; /** * Mapping 命名策略 */ @Nullable private HandlerMethodMappingNamingStrategy<T> namingStrategy; /** * Mapping 注册表 */ private final MappingRegistry mappingRegistry = new MappingRegistry(); }
<T>
泛型,就是咱们前面要一直提到的 Mapping 类型
mappingRegistry
:Mapping 注册表,详细见下文
namingStrategy
:org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy
接口,HandlerMethod 的 Mapping 的名字生成策略接口
@FunctionalInterface public interface HandlerMethodMappingNamingStrategy<T> { /** * 根据 HandlerMethod 获取名称,就是为对应的 Mappring 对象生成一个名称,便于获取 */ String getName(HandlerMethod handlerMethod, T mapping); } // org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMethodMappingNamingStrateg.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(); } }
@RequestMapping(name = "login", value = "user/login")
注解的方法,它对应的 Mapping 的名字就是 login
"#"
+ 方法名。例如,@RequestMapping(value = "user/login")
注解的方法,假设它所在的类为 UserController ,对应的方法名为 login ,则它对应的 Mapping 的名字就是 USERCONTROLLER#login
AbstractHandlerMethodMapping 的内部类,Mapping 注册表
class MappingRegistry { /** * 注册表 * * Key: Mapping * Value:{@link MappingRegistration}(Mapping + HandlerMethod) */ private final Map<T, MappingRegistration<T>> registry = new HashMap<>(); /** * 注册表2 * * Key:Mapping * Value:{@link HandlerMethod} */ 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<>(); private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>(); /** * 读写锁 */ private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); }
registry
:注册表。Key: Mapping,即 <T>
泛型;Value:MappingRegistration 对象(Mapping + HandlerMethod)mappingLookup
:注册表2。Key: Mapping,即 <T>
泛型;Value:HandlerMethod 对象urlLookup
:直接 URL 的映射。Key:直接 URL(就是固定死的路径,而非多个);Value:Mapping 数组nameLookup
:Mapping 的名字与 HandlerMethod 的映射。Key:Mapping 的名字;Value:HandlerMethod 数组readWriteLock
:读写锁,为了才操做上述属性时保证线程安全register(T mapping, Object handler, Method method)
方法,将 Mapping、Method、handler(方法所在类)之间的映射关系进行注册,会生成 HandlerMethod 对象,就是处理器对象,方法以下:
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 是否存在对应的 HandlerMethod 对象,若是已存在但不是当前的 handlerMethod 对象则抛出异常 assertUniqueMethodMapping(handlerMethod, mapping); // <2.3> 将 mapping 与 handlerMethod 的映射关系保存至 this.mappingLookup this.mappingLookup.put(mapping, handlerMethod); // <3.1> 得到 mapping 对应的普通 URL 数组 List<String> directUrls = getDirectUrls(mapping); // <3.2> 将 url 和 mapping 的映射关系保存至 this.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 的映射关系保存至 this.nameLookup addMappingName(name, handlerMethod); } // <5> 初始化 CorsConfiguration 配置对象 CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } // <6> 建立 MappingRegistration 对象 // 并与 mapping 映射添加到 registry 注册表中 this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name)); } finally { // <7> 释放写锁 this.readWriteLock.writeLock().unlock(); } }
得到写锁
添加相关映射至Map<T, HandlerMethod> mappingLookup
属性
createHandlerMethod(Object handler, Method method)
方法,建立 HandlerMethod 对象,详情见下文mappingLookup
添加相关映射至MultiValueMap<String, T> urlLookup
属性
调用 getDirectUrls
方法,得到 Mapping 对应的直接 URL 数组,以下:
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}")
注解对应的路径,不是直接路径,由于不肯定性将 url 和 Mapping 的映射关系保存至 urlLookup
添加相关映射至Map<String, List<HandlerMethod>> nameLookup
属性
调用 HandlerMethodMappingNamingStrategy#getName(HandlerMethod handlerMethod, T mapping)
方法,得到 Mapping 的名字
调用 addMappingName(String name, HandlerMethod handlerMethod)
方法,添加 Mapping
的名字 + HandlerMethod 至 nameLookup
,以下:
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); }
和已有的进行合并,说明名称不是惟一哦
初始化 CorsConfiguration 配置对象,暂时忽略
建立 MappingRegistration
对象,并和 Mapping 进行映射添加至 registry
释放写锁
unregister(T mapping)
方法,取消上面方法注册的相关信息,方法以下:
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(); }
和 register
方法逻辑相反,依次移除相关映射
createHandlerMethod(Object handler, Method method)
方法,建立 Method 对应的 HandlerMethod 对象
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; }
@Controller
注解后,默认入参 handler 就是它的 beanName ,即 userController
因此你会发现 HandlerMethod 处理器对象,就是handler(方法所在类)
+method(方法对象)
的组合,经过它能执行该方法
org.springframework.web.method.HandlerMethod
,处理器对象,也就是某个方法的封装对象(Method+所在类的 Bean 对象),有如下属性:
public class HandlerMethod { /** * Bean 对象 */ private final Object bean; @Nullable private final BeanFactory beanFactory; /** * Bean 的类型 */ private final Class<?> beanType; /** * 方法对象 */ private final Method method; /** * {@link #method} 的桥接方法 * 存在泛型类型,编译器则会自动生成一个桥接方法(java1.5向后兼容) */ 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; }
根据上面的注释理解上面的属性,包含该方法的全部信息
它的构造函数很是多,不过原理都差很少,咱们挑两个来看看
HandlerMethod(String beanName, BeanFactory beanFactory, Method method) 构造方法
对应 createHandlerMethod(Object handler, Method method)
方法的 <1>
,代码以下:
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 属性,经过 @ResponseStatus 注解 evaluateResponseStatus(); }
将 beanName
赋值给 bean
属性,说明 beanFactory + bean
的方式,得到 handler
对象
初始化 beanType
属性
初始化 method
、bridgedMethod
属性
初始化 parameters
属性,解析该方法(或者桥接方法)的参数类型,调用 initMethodParameters()
方法,以下:
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; }
初始化 responseStatus
、responseStatusReason
属性,经过 @ResponseStatus
注解
关于桥接方法呢,是 java1.5 引入泛型向后兼容的一种方法,具体可参考Effects of Type Erasure and Bridge Methods
HandlerMethod(Object bean, Method method) 构造方法
对应 createHandlerMethod(Object handler, Method method)
方法的 <2>
,代码以下:
public HandlerMethod(Object bean, Method method) { Assert.notNull(bean, "Bean is required"); Assert.notNull(method, "Method is required"); // <1> 初始化 Bean this.bean = bean; this.beanFactory = null; // <2> 初始化 beanType 属性 this.beanType = ClassUtils.getUserClass(bean); // <3> 初始化 method、bridgedMethod 属性 this.method = method; // 若是不是桥接方法则直接为该方法 this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); // <4> 初始化 parameters 属性,解析该方法(或者桥接方法)的参数类型 this.parameters = initMethodParameters(); // <5> 初始化 responseStatus、responseStatusReason 属性,经过 @ResponseStatus 注解 evaluateResponseStatus(); }
和上面的构造方法差很少,不一样的是这里的 bean
对象就是方法所在类的 Bean 对象
AbstractHandlerMethodMapping 的私有静态内部类,Mapping 的注册登记信息,包含 Mapiing、HandlerMethod、直接 URL 路径、Mapping 名称,代码以下:
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; } }
很简单,就是保存了 Mapping 注册时的一些信息
由于 AbstractHandlerMethodMapping 实现了 InitializingBean 接口,在 Sping 初始化该 Bean 的时候,会调用该方法,完成一些初始化工做,方法以下:
@Override public void afterPropertiesSet() { // <x> 初始化处理器的方法们 initHandlerMethods(); } protected void initHandlerMethods() { // <1> 遍历 Bean ,逐个处理 for (String beanName : getCandidateBeanNames()) { // 排除目标代理类,AOP 相关,可查看注释 if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { // <2> 处理 Bean processCandidateBean(beanName); } } // <3> 初始化处理器的方法们,目前是空方法,暂无具体的实现 handlerMethodsInitialized(getHandlerMethods()); }
调用 getCandidateBeanNames()
方法,获取到 Spring 上下文中全部为 Object
类型的 Bean 的名称集合,而后进行遍历,方法以下:
protected String[] getCandidateBeanNames() { // 获取上下文中全部的 Bean 的名称 return (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) : obtainApplicationContext().getBeanNamesForType(Object.class)); }
detectHandlerMethodsInAncestorContexts
:是否只扫描可访问的 HandlerMethod 们,默认false
调用 processCandidateBean(String beanName)
方法,处理每一个符合条件的 Bean 对象(例若有 @Controller
或者 @RequestMapping
注解的 Bean),解析这些 Bean 下面相应的方法,往 MappingRegistry
注册,详情见下文
调用 handlerMethodsInitialized(Map<T, HandlerMethod> handlerMethods)
方法,初始化 HandlerMethod 处理器们,空方法,暂无子类实现
processCandidateBean(String beanName)
方法,处理符合条件的 Bean 对象,解析其相应的方法,往 MappingRegistry
注册,方法以下:
protected void processCandidateBean(String beanName) { // <1> 得到 Bean 对应的 Class 对象 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); } } // <2> 判断 Bean 是否为处理器(例若有 @Controller 或者 @RequestMapping 注解) if (beanType != null && isHandler(beanType)) { // <3> 扫描处理器方法 detectHandlerMethods(beanName); } }
isHandler(Class<?> beanType)
抽象方法,判断 Bean 的类型是否须要处理,其 RequestMappingHandlerMapping
子类的实现:有 @Controller
或者 @RequestMapping
注解的 BeandetectHandlerMethods(Object handler)
方法,扫描 Bean 的方法进行处理detectHandlerMethods(Object handler)
方法,初始化 Bean 下面的方法们为 HandlerMethod 对象,并注册到 MappingRegistry 注册表中,代码以下:
protected void detectHandlerMethods(Object handler) { // <1> 得到 Bean 对应的 Class 对象 Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { // <2> 得到真实的 Class 对象,由于 `handlerType` 多是代理类 Class<?> userType = ClassUtils.getUserClass(handlerType); // <3> 得到匹配的方法和对应的 Mapping 对象 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { // 建立该方法对应的 Mapping 对象,例如根据 @RequestMapping 注解建立 RequestMappingInfo 对象 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)); } // <4> 遍历方法,逐个注册 HandlerMethod methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } }
得到 Bean 对应的 Class 对象 handlerType
调用getUserClass(Class<?> clazz)
方法,得到真实的 Class 对象,由于 handlerType
多是代理类,以下:
public static Class<?> getUserClass(Class<?> clazz) { // 若是 Class 对象的名称包含 "$$",则是 CG_CLASS 代理类,则获取其父类 if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { Class<?> superclass = clazz.getSuperclass(); if (superclass != null && superclass != Object.class) { return superclass; } } return clazz; }
得到匹配的方法和对应的 Mapping 对象,其中泛型 T
,也就是 Mapping 对象,须要经过 getMappingForMethod(Method method, Class<?> handlerType)
抽象方法返回,其 RequestMappingHandlerMapping
子类的实现,根据 @RequestMapping
注解为方法建立 RequestMappingInfo
对象
因此这里的 Mapping 对象就是 RequestMappingInfo
对象
遍历方法(方法与 Mapping 一一映射了),调用registerHandlerMethod(Object handler, Method method, T mapping)
,逐个注册对应的 HandlerMethod 对象,以下:
protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); }
也就是上面 MappingRegistry 的 register 方法,已经分析过了😄
到这里咱们已经分析完了 AbstractHandlerMethodMapping 的初始化工做,部分细节在子类中实现
大体逻辑:扫描有
@Controller
或者@RequestMapping
注解的类下面的方法,若是方法上面有@RequestMapping
注解,则会为该方法建立对应的RequestMappingInfo
对象将全部的
RequestMappingInfo
对象和 Method 以及方法所在类,往 MappingRegistry 进行注册,会生成 HandlerMethod 处理器(Method 全部信息)对象这样一来,当 Spring MVC 的 DispatcherServlet 处理请求的时候,获取到对应的 HandlerMethod 处理器,就能够经过反射执行对应的方法了
到这里,思路是否是愈来愈清晰了,咱们继续往下分析
因为上面初始化涉及到内容有点多,先回到本文上面的回顾这一小节,经过 AbstractHandlerMapping 的
getHandler(HttpServletRequest request)
方法获取 HandlerExecutionChain 处理器执行链时,须要调用getHandlerInternal
抽象方法获取处理器,这个方法由子类去实现,就到这里了
getHandlerInternal(ServerWebExchange exchange)
方法,得到请求对应的 HandlerMethod 处理器对象,方法以下:
@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 对象,以下:
public HandlerMethod createWithResolvedBean() { Object handler = this.bean; // 若是是 bean 是 String 类型,则获取对应的 Bean,由于建立该对象时 bean 多是对应的 beanName 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); } return new HandlerMethod(this, handler); }
释放读锁
lookupHandlerMethod(ServerWebExchange exchange)
方法,得到请求对应的 HandlerMethod 处理器对象,方法以下:
@Nullable protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { // <1> Match 数组,存储匹配上当前请求的结果(Mapping + HandlerMethod) 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); } 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 + "}"); } } request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); // <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); } }
定义 Match 数组 matches
,存储匹配上当前请求的结果(Mapping
+ HandlerMethod
)
Mapping
们,进行匹配上述的1.1
和1.2
,都会调用addMatchingMappings(Collection<T> mappings, List<Match> matches, ServerWebExchange exchange)
方法
将当前请求和注册表中的 Mapping 进行匹配,匹配成功则生成匹配结果 Match,添加到 matches
中,方法以下:
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) { // 遍历 Mapping 数组 for (T mapping : mappings) { // <1> 执行匹配,抽象方法,交由子类实现 T match = getMatchingMapping(mapping, request); if (match != null) { // <2> 若是匹配,则建立 Match 对象,添加到 matches 中 matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping))); } } }
若是匹配到,则获取最佳匹配的 Match 结果的 HandlerMethod
属性
matches
的结果,排序器lookupPath
到请求属性HandlerMethod
处理器对象若是匹配不到,则处理不匹配的状况,调用handleNoMatch(Set<T> mappings, String lookupPath, HttpServletRequest request)
方法,这里返回null
到这里 AbstractHandlerMethodMapping 抽象类差很少所有分析完了,其中有几个抽象方法交由子类去实现
protected abstract boolean isHandler(Class<?> beanType);
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
protected abstract Set<String> getMappingPathPatterns(T mapping);
protected abstract T getMatchingMapping(T mapping, HttpServletRequest request);
protected abstract Comparator<T> getMappingComparator(HttpServletRequest request);
org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping
,继承 AbstractHandlerMethodMapping 抽象类,定义了使用的泛型 <T>
为 org.springframework.web.servlet.mvc.method.RequestMappingInfo
类,即 Mapping 类型就是 RequestMappingInfo 对象
这样有什么好处呢?
RequestMappingInfoHandlerMapping
定义了使用 RequestMappingInfo
对象,而其子类 RequestMappingHandlerMapping
将使用了 @RequestMapping
注解的方法,解析生成 RequestMappingInfo
对象。这样,若是将来咱们本身定义注解,或者其余方式来生成 RequestMappingHandlerMapping
对象,何尝不可。
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> { protected RequestMappingInfoHandlerMapping() { // 设置父类的 namingStrategy 属性 Mapping 命名策略对象,为 RequestMappingInfoHandlerMethodMappingNamingStrategy 对象 setHandlerMethodMappingNamingStrategy(new RequestMappingInfoHandlerMethodMappingNamingStrategy()); } }
<T>
泛型,为 RequestMappingInfo
类型
设置父类 AbstractHandlerMethodMapping
的 namingStrategy
属性为 RequestMappingInfoHandlerMethodMappingNamingStrategy
对象
是否还记得这个为 Mapping 生成名称的类?在 AbstractHandlerMethodMapping 中进行分析过了
RequestMappingInfo 不是 RequestMappingInfoHandlerMapping 的内部类,而是 RequestMappingInfoHandlerMapping 的前缀
org.springframework.web.servlet.mvc.method.RequestMappingInfo
,实现 RequestCondition 接口,每一个方法的定义的请求信息,也就是 @RequestMapping
等注解的信息
关于
org.springframework.web.servlet.mvc.condition.RequestCondition
,条件接口,定义了三个方法,分别是:
combine(T other)
,合并方法getMatchingCondition(HttpServletRequest request)
,匹配方法compareTo(T other, HttpServletRequest request)
,比较方法
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> { /** * 名字 */ @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
请求方法条件RequestCondition 接口体系结构以下:
getMatchingCondition(HttpServletRequest request)
方法,从当前 RequestMappingInfo 得到匹配的条件。若是匹配,则基于其匹配的条件,建立新的 RequestMappingInfo 对象,若是不匹配,则返回 null
,代码以下:
@Override @Nullable public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { // 匹配 methodsCondition、paramsCondition、headersCondition、consumesCondition、producesCondition // 若是任一为空,则返回 null ,表示匹配失败 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; } /* * 建立匹配的 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 对象,而且在匹配时,直接返回自身,代码以下:
@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()); }
也就是说,没有 RequestMethod 的条件,则必定匹配成功,且结果就是自身 RequestMethodsRequestCondition 对象
总结:就是根据配置的 @RequestMapping
注解,若是全部条件都知足,则建立一个 RequestMappingInfo 对象返回,若是某个条件不知足则直接返回 null
,表示不匹配
compareTo(RequestMappingInfo other, HttpServletRequest request)
方法,比较优先级,方法以下:
@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、paramsCondition、headersCondition、consumesCondition、 * producesCondition、methodsCondition、customConditionHolder * 若是有一个不相等,则直接返回比较结果 */ 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; }
关于各类 RequestCondition 请求条件就不一一分析了
getMappingPathPatterns(RequestMappingInfo info)
方法,得到 RequestMappingInfo 对应的请求路径集合,代码以下:
@Override protected Set<String> getMappingPathPatterns(RequestMappingInfo info) { return info.getPatternsCondition().getPatterns(); }
register
方法中的第 3
步会调用,将全部符合的请求路径与该 RequestMappingInfo 对象进行映射保存getMatchingMapping(RequestMappingInfo info, HttpServletRequest request)
方法,判断请求是否匹配入参 RequestMappingInfo 对象,代码以下:
@Override protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) { return info.getMatchingCondition(request); }
lookupHandlerMethod
获取处理器方法的<1.1>
和<1.2>
会调用,遍历全部的 Mapping 对象,获取到该请求所匹配的 RequestMappingInfo 对象handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request)
方法,覆写父类的方法,设置更多的属性到请求中,代码以下:
@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(Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request)
方法,覆写父类方法,处理无匹配 Mapping 的状况
主要用途是,给出为何找不到 Mapping 的缘由,代码以下:
@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); } // <3> 可消费的 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)); } // <4> 可生产的 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 中实现,暂时忽略😈
方法错误。这是一个很是常见的错误,例如说 POST user/login
存在,可是咱们请求了 GET user/login
可消费的 Content-Type 错误
可生产的 Content-Type 错误
参数错误
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
,实现 MatchableHandlerMapping、EmbeddedValueResolverAware 接口,继承 RequestMappingInfoHandlerMapping 抽象类,基于@RequestMapping
注解来构建 RequestMappingInfo 对象
写到这里有那么一点点感动,终于到最底层的实现类了😢
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping implements MatchableHandlerMapping, EmbeddedValueResolverAware { 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 的构建器 */ private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration(); }
由于父类 AbstractHandlerMethodMapping 实现了 InitializingBean 接口,在 Sping 初始化该 Bean 的时候,会调用该方法,完成一些初始化工做,方法以下:
@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(); }
是否还记得 AbstractHandlerMethodMapping 的这个抽象方法?在它的 processCandidateBean
方法中,扫描 Spring 中全部 Bean 时会调用,判断是否须要扫描这个 Bean 中的方法,方法以下:
@Override protected boolean isHandler(Class<?> beanType) { // 判断是否有 @Controller 或者 @RequestMapping 的注解 return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }
有 @Controller
或者 @RequestMapping
的注解的类才须要进行扫描,是否是很熟悉😈
是否还记得 AbstractHandlerMethodMapping 的这个抽象方法?在它的 detectHandlerMethods
方法中,用于获取 Method 方法对应的 Mapping 对象,方法以下:
@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).options(this.config).build().combine(info); } } return info; }
调用 createRequestMappingInfo(AnnotatedElement element)
方法,基于方法上的 @RequestMapping
注解,建立 RequestMappingInfo
对象
@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); } 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
注解,合并进去
若是有前缀,则设置到 info
中
match(HttpServletRequest request, String pattern)
方法,执行匹配,代码以下:
@Override public RequestMatchResult match(HttpServletRequest request, String pattern) { // <1> 为 `pattern` 建立一个 RequestMappingInfo 对象 RequestMappingInfo info = RequestMappingInfo.paths(pattern).options(this.config).build(); // <2> 得到请求对应的 RequestMappingInfo 对象 RequestMappingInfo matchingInfo = info.getMatchingCondition(request); if (matchingInfo == null) { // <3> 没有匹配的 RequestMappingInfo 对象返回空 return null; } // <4> 得到请求匹配到的路径 Set<String> patterns = matchingInfo.getPatternsCondition().getPatterns(); // <5> 获取请求路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // <6> 建立 RequestMatchResult 结果 return new RequestMatchResult(patterns.iterator().next(), lookupPath, getPathMatcher()); }
在 Spring MVC 处理请求的过程当中,须要经过 HandlerMapping 组件会为请求找到合适的 HandlerExecutionChain
处理器执行链,包含处理器(handler
)和拦截器们(interceptors
),该组件体系结构以下:
本文就红色框中的内容进行了分析,基于 Method 进行匹配。例如,咱们所熟知的 @RequestMapping
等注解的方式
在将红色框中的类注入到 Spring 上下文时,会进行一些初始化工做,扫描 @Controller
或者 @RequestMapping
注解标注的 Bean 对象,会将带有 @RequestMapping
注解(包括其子注解)解析成 RequestMappingInfo
对象。接下来,会将 RequestMappingInfo
、该方法对象
、该方法所在类对象
往 MappingRegistry
注册表进行注册,其中会生成 HandlerMethod
处理器(方法的全部信息)对象保存起来。当处理某个请求时,HandlerMapping 找到该请求对应的 HandlerMethod
处理器对象后,就能够经过反射调用相应的方法了
这部份内容包含了咱们经常使用到 @Controller
和 @RequestMapping
注解,算是 HandlerMapping 组件的核心内容,看完以后有种茅塞顿开的感受
回到之前的 Servlet 时代,咱们须要编写许多的 Servlet 去处理请求,而后在 web.xml 中进行配置,而 Spring MVC 让你经过只要在类和方法上面添加 @Controller
或者 @RequestMapping
注解这种方式,就能够处理请求,由于全部的请求都交给了 DispatcherServlet 去处理。这样是否是简化了你的工做量,让你专一于业务开发。
参考文章:芋道源码《精尽 Spring MVC 源码分析》