SpringMVC源码(六):Handler处理器
在MVC请求流程中,Handler处理器依赖于HandlerMapping组件。因此在处理客户端请求时,会优先获取HandlerMapping处理器。
HandlerMapping组件主要作用是根据客户端的访问路径,匹配到Controller处理器及对应的Method处理方法并将其包装在HandlerMethod兑现中。用处理器执行链对象HandlerExecutionChain对象包装HandlerMethod,并在处理器执行链对象中添加拦截器。
1、处理器执行链HandlerExecutionChain结构介绍
处理器执行链中的handler属性包含了请求要调用的目标Controller处理器、Method方法及MethodParameter方法中的参数,只要获取到HandlerExecutionChain对象,就已经锁定了请求需要调用哪个Controller中的哪个处理方法。
下面我们来看看是处理器执行链HandlerExecutionChain是如何获取到的。
2、HandlerExectionChain对象的获取
2.1、获取HandlerExectionChain准备工作
1、映射器处理器handlerMappings
在源码(三):MVC九大内置组件初始化中有提到,处理器映射器handlerMappings为DispatcherServlet中的属性,在HandlerMapping初始化时,会对handlerMappings集合做初始化操作。
handlerMappings集合中有三个HandlerMapping处理器,分别为RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping。
1、RequestMappingHandlerMapping
RequestMappingHandlerMapping的作用:在@Controller注解中的控制器中,根据类型和@RequestMapping注解中的内容, 创建RequestMappingInfo实例。类图结构如下:
2、BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping的作用:实现了HandlerMapping接口,筛选出 beanName 或者 别名以 "/" 开头的 Bean ,将这些 Bean 注册为 “Handler”,实现 URL 映射。类图结构如下:
3、SimpleUrlHandlerMapping
在实际研发过程中,最常用的是@Controlelr、@RequestMapping,即RequestMappingHandlerMapping类型的HnalderMapping最为常用,本次源码分析以RequestMappingHandlerMapping为例。
2、AbstractHandlerMethodMapping#mappingRegistry初始化
在SpringMVC容器启动过程中,创建MVC容器中单例的bean步骤,创建HandlerMapping组件中的RequestMappingHandlerMapping对象,在初始化RequestMappingHandlerMapping的bean,在invokeInitMethods()逻辑的afterPropertiesSet()会对mappingRegistry做初始化。
FrameworkServlet#configureAndRefreshWebApplicationContext()
-> AbstractApplicationContext#refresh()
-> DefaultListableBeanFactory#preInstantiateSingletons()
-> AbstractBeanFactory#getBean() -> AbstractBeanFactory#doGetBean()
-> AbstractAutowireCapableBeanFactory#createBean() -> AbstractAutowireCapableBeanFactory#doCreateBean()
-> AbstractAutowireCapableBeanFactory#initializeBean() bean的初始化
-> AbstractAutowireCapableBeanFactory#invokeInitMethods() 调用bean初始化方法
-> RequestMappingHandlerMapping#afterPropertiesSet() 调用bean的afterPropertiesSet方法
初始化HandlerMapping对象属性,RequestMappingHandlerMapping#afterPropertiesSet() 核心伪代码:
1 // 初始化HandlerMapping对象属性 2 public void afterPropertiesSet() { 3 this.config = new RequestMappingInfo.BuilderConfiguration(); 4 // 初始化url帮助器 5 this.config.setUrlPathHelper(getUrlPathHelper()); 6 // 初始化路径匹配器 7 this.config.setPathMatcher(getPathMatcher()); 8 this.config.setSuffixPatternMatch(useSuffixPatternMatch()); 9 this.config.setTrailingSlashMatch(useTrailingSlashMatch()); 10 this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch()); 11 this.config.setContentNegotiationManager(getContentNegotiationManager()); 12 13 // 初始化父类HandlerMapping属性 14 super.afterPropertiesSet(); 15 }
AbstractHandlerMethodMapping#afterPropertiesSet()
-> AbstractHandlerMethodMapping#initHandlerMethods()
父类属性初始化,AbstractHandlerMethodMapping#initHandlerMethods()核心伪代码:
1 // 原型对象前缀 2 private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget."; 3 4 // 初始化handlerMapping组件属性 5 protected void initHandlerMethods() { 6 // 获取MVC容器中,所有的beanName 7 for (String beanName : getCandidateBeanNames()) { 8 // beanName不以scopedTarget.为前缀 9 if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { 10 // 处理候选的beanName 11 processCandidateBean(beanName); 12 } 13 } 14 15 handlerMethodsInitialized(getHandlerMethods()); 16 }
处理候选的bean, AbstractHandlerMethodMapping#processCandidateBean核心伪代码:
1 // 处理候选的bean 2 protected void processCandidateBean(String beanName) { 3 // 获取beanName对应的Class对象 4 Class<?> beanType = obtainApplicationContext().getType(beanName); 5 6 // RequestMappingHandlerMapping#isHandler bean被Controller、RequestMapping注解修饰 7 if (beanType != null && isHandler(beanType)) { 8 // 处理Hnalder方法 9 detectHandlerMethods(beanName); 10 } 11 }
获取Controller处理器的方法 AbstractHandlerMethodMapping#detectHandlerMethods() 核心伪代码:
1 // 获取Controller处理器的方法 2 protected void detectHandlerMethods(Object handler) { 3 // 获取Handler的Class对象 4 Class<?> handlerType = (handler instanceof String ? 5 obtainApplicationContext().getType((String) handler) : handler.getClass()); 6 // Class对象不为空 7 if (handlerType != null) { 8 // 获取Class对象 9 Class<?> userType = ClassUtils.getUserClass(handlerType); 10 // 获取访问路径与Controller处理器方法的映射关系 11 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, 12 (MethodIntrospector.MetadataLookup<T>) method -> { 13 return getMappingForMethod(method, userType); 14 }); 15 16 // 注册 17 methods.forEach((method, mapping) -> { 18 Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); 19 registerHandlerMethod(handler, invocableMethod, mapping); 20 }); 21 } 22 }
1、获取Class对象
获取Handler(@Controller、@RequestMapping注解修饰的)的Class对象
2、构建访问路径与Handler处理器的映射关系
根据访问路径,获取Handler处理器中的目标方法,并构建访问路径与Controller处理器方法的映射关系
3、注册映射关系,初始化mappingRegistry
RequestMappingHandlerMapping#registerHandlerMethod()
-> AbstractHandlerMethodMapping#registerHandlerMethod()
初始化mappingRegistry,注冊HandlerMethod至mappingRegistry, AbstractHandlerMethodMapping#registerHandlerMethod() 核心伪代码:
1 // 注册handlerMethod至AbstractHandlerMethodMapping的mappingRegistry 2 rotected void registerHandlerMethod(Object handler, Method method, T mapping) { 3 // 注册 4 this.mappingRegistry.register(mapping, handler, method); 5 }
参数详情:
2.2、核心流程图
2.3、核心流程源码分析
遍历handlerMappings并返回request对应的处理器和拦截器,以下是整体流程的核心伪代码。
DispatcherServlet#getHandler 核心伪代码
1 // 获取处理器执行链对象 2 protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 3 // SpringMVC默认实现三种类型的HandlerMapping: 4 // RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping 5 if (this.handlerMappings != null) { 6 // 遍历MVC容器中的处理器映射器 7 for (HandlerMapping mapping : this.handlerMappings) { 8 // 获取请求对应的处理器执行链 9 HandlerExecutionChain handler = mapping.getHandler(request); 10 // 处理器执行链不为空 11 if (handler != null) { 12 // 返回匹配到的处理器执行链 13 return handler; 14 } 15 } 16 } 17 // 返回null 18 return null; 19 }
AbstractHandlerMapping#getHandler 核心伪代码
1 // 为请求获取handler处理器,若没有Handler处理器,获取mvc默认的handler处理器 2 public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 3 // 获得处理器(HandlerMethod或者HandlerExecutionChain),该方法是抽象方法,由子类实现 4 Object handler = getHandlerInternal(request); 5 // 获得不到,则使用默认处理器 6 if (handler == null) { 7 handler = getDefaultHandler(); 8 } 9 // 获得不到,则返回 null 10 if (handler == null) { 11 return null; 12 } 13 14 // 如果找到的处理器是String类型,则从Spring容器中找到对应的Bean作为处理器 15 if (handler instanceof String) { 16 String handlerName = (String) handler; 17 handler = obtainApplicationContext().getBean(handlerName); 18 } 19 20 // 创建HandlerExecutionChain对象(包含处理器和拦截器) 21 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); 22 23 // 跨域请求的处理 24 if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) { 25 CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null); 26 CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); 27 config = (config != null ? config.combine(handlerConfig) : handlerConfig); 28 executionChain = getCorsHandlerExecutionChain(request, executionChain, config); 29 } 30 31 return executionChain; 32 }
1、根据request请求获取handler处理器
AbstractHandlerMethodMapping#getHandlerInternal 核心伪代码
1 / 为request请求查找handler处理器 2 protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { 3 // 获取访问的路径 4 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); 5 request.setAttribute(LOOKUP_PATH, lookupPath); 6 // 获得读锁 7 this.mappingRegistry.acquireReadLock(); 8 try { 9 // 获取HandlerMethod作为handler对象,涉及到路径匹配的优先级 10 // 优先级: 精确匹配>最长路径匹配>扩展名匹配 获取Controller及内部方法 11 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); 12 // handlerMethod内部包含有bean对象,创建目标controller对象 13 return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); 14 } 15 finally { 16 // 释放读锁 17 this.mappingRegistry.releaseReadLock(); 18 } 19 }
1.1、获取HandlerMethod对象
该步骤主要用于获取HandlerMethod对象,从HandlerMethod对象的关键属性中可以看出,获取到了HandlerMethod对象等同于知道了请求要调用哪个Controller的哪个Method方法。
AbstractHandlerMethodMapping#lookupHandlerMethod 核心伪代码
1 // 查找request请求对应的HandlerMethod对象(Controller处理器及调用方法) 2 protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { 3 // Match数组,存储匹配上当前请求的结果(Mapping + HandlerMethod) 4 List<Match> matches = new ArrayList<>(); 5 // 首先根据lookupPath获取到匹配条件 6 List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); 7 if (directPathMatches != null) { 8 // 将找到的匹配条件添加到matches 9 addMatchingMappings(directPathMatches, matches, request); 10 } 11 // 如果不能直接使用lookupPath得到匹配条件,则将所有匹配条件加入matches 12 if (matches.isEmpty()) { 13 addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); 14 } 15 16 // 将包含匹配条件和handler的matches排序,并取第一个作为bestMatch,如果前面两个排序相同则抛出异常 17 if (!matches.isEmpty()) { 18 Match bestMatch = matches.get(0); 19 if (matches.size() > 1) { 20 // 创建排序器,MatchComparator对象,排序matches元素 21 Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); 22 matches.sort(comparator); 23 // 获得首个Match对象,也就是最匹配的 24 bestMatch = matches.get(0); 25 if (CorsUtils.isPreFlightRequest(request)) { 26 return PREFLIGHT_AMBIGUOUS_MATCH; 27 } 28 // 比较bestMatch和secondBestMatch,如果相等,抛出IllegalStateException异常,如果两个优先级一样高,说明无法判断谁更优先 29 Match secondBestMatch = matches.get(1); 30 if (comparator.compare(bestMatch, secondBestMatch) == 0) { 31 Method m1 = bestMatch.handlerMethod.getMethod(); 32 Method m2 = secondBestMatch.handlerMethod.getMethod(); 33 String uri = request.getRequestURI(); 34 throw new IllegalStateException( 35 "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}"); 36 } 37 } 38 request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); 39 // 处理首个Match对象 40 handleMatch(bestMatch.mapping, lookupPath, request); 41 // 返回首个Match对象的handlerMethod属性 42 return bestMatch.handlerMethod; 43 } 44 // 如果匹配不到,则处理不匹配的情况,抛出异常 45 else { 46 return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); 47 } 48 }
1、获取匹配结果matchs
根据访问路径获取到AbstractHandlerMethodMapping#mappingRegistry属性中的匹配条件,若能从mappingRegistr获取到匹配条件,并将匹配到的结果HandlerMethod对象加入matchs集合中,获取到matchs集合详情如下
如果不能从mappingRegistr获取到匹配条件,则将mappingRegistr中所有的匹配条件加入matches集合中。
2、返回HandlerMethod对象
matchs集合中的元素个数大于1,创建MatchComparator对象,并将matches元素排序,获取首个最为匹配的HandlerMethod对象并返回。
1.2、创建Controller处理
如果获取的Handler处理器的bean属性为String类型,表示获取到了Controller处理器的beanName,创建目标Controller处理器。
HandlerMethod#createWithResolvedBean 核心伪代码:
1 // 创建Controller处理器 2 public HandlerMethod createWithResolvedBean() { 3 // 获取handler处理器 4 Object handler = this.bean; 5 // handelr处理器为String类型 6 if (this.bean instanceof String) { 7 // 获取Controller的beanName 8 String beanName = (String) this.bean; 9 // 创建Controller的处理器 10 handler = this.beanFactory.getBean(beanName); 11 } 12 // 创建handlerMethod对象,封装handler处理器 13 return new HandlerMethod(this, handler); 14 }
1、 HandlerMethod#createWithResolvedBean中的获取的handler处理器
HandlerMethod#createWithResolvedBean中创建的handler是Controller处理器。获取的Handler处理器详情:
2、AbstractHandlerMapping#getHandler中获取的handler处理器详情
AbstractHandlerMapping#getHandler中获取的Handlers是HandlerMethod,持有HandlerMethod#createWithResolvedBean中创建的Controller处理器对象,获取到HandlerMethod详情:
2、若获取到的handler处理器为空,则获取默认的handler处理器
在源码(三):MVC九大内置组件初始化中,在初始化HandlerMapping组件时,如果用户未自定义HandlrMapping时,SpringMVC会加载DispatcherServlet.properties配置文件中默认的HandlerMapping对象:BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、RouterFunctionMapping。
3、若默认的handler处理器为空,则返回null
4、如果默认的handler处理器不为空,并且handler类型为String,创建handler的beanName创建handler对象
5、创建HandlerExecutionChain对象
创建handlerExecutionChain对象,包装handler处理器和拦截器。
1 // 为handler处理器构建HandlerExecutionChain对象,包含应用拦截器 2 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { 3 // 创建 HandlerExecutionChain 对象 4 HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? 5 (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); 6 7 // 获得请求路径 8 String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH); 9 // 遍历 adaptedInterceptors 数组,获得请求匹配的拦截器 10 for (HandlerInterceptor interceptor : this.adaptedInterceptors) { 11 // 需要匹配,若路径匹配,则添加到 chain 中 12 if (interceptor instanceof MappedInterceptor) { 13 MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; 14 if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { 15 chain.addInterceptor(mappedInterceptor.getInterceptor()); 16 } 17 } 18 // 无需匹配,直接添加到 chain 中 19 else { 20 chain.addInterceptor(interceptor); 21 } 22 } 23 return chain; 24 }
1、handler处理器是否为HandlerExecutionChain类型,若不是HandlerExecutionChain类型,创建HandlerExecutionChain对象,封装handler处理器器。
2、获取访问路径,根据访问路径获取处理器拦截器 AbstractHandlerMapping#adaptedInterceptors 中的应用拦截器。若拦截器为MappedInterceptor类型,则通过访问路径,匹配对应的拦截器;否则,直接添加进HandlerExecutionChain的interceptorList属性中。
6、跨域请求的处理
7、返回handlerExecutionChain对象