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
  SimpleUrlHandlerMapping的作用:实现了HandlerMapping接口,明确指定URL和Handler的映射关系,显式声明 URL与 Handler的 映射。类图结构如下:

  

  在实际研发过程中,最常用的是@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方法。

  0

  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集合详情如下

   0

  如果不能从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详情:

    0

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处理器器。

 0

  2、获取访问路径,根据访问路径获取处理器拦截器 AbstractHandlerMapping#adaptedInterceptors 中的应用拦截器。若拦截器为MappedInterceptor类型,则通过访问路径,匹配对应的拦截器;否则,直接添加进HandlerExecutionChain的interceptorList属性中。

 0

6、跨域请求的处理

7、返回handlerExecutionChain对象

 

posted @ 2023-02-14 21:39  无虑的小猪  阅读(410)  评论(0编辑  收藏  举报