美文网首页JAVA学习文集
SpringMVC详解-请求分发流程之处理器 HandlerMa

SpringMVC详解-请求分发流程之处理器 HandlerMa

作者: 小燃儿 | 来源:发表于2020-10-28 16:32 被阅读0次

    上篇文章《SpringMVC详解-怎么接收请求》已经提到过了,当Servlet接收到请求后会最终调用doDispatch方法(这里省略部分代码保留主要功能):

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
            // 1.确定使用的handler
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
              noHandlerFound(processedRequest, response);
              return;
            }
    
            // 确定handler的适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
            // 拦截器前置调用
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
              return;
            }
    
            // 实际调用
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            // 设置默认视图名
            applyDefaultViewName(processedRequest, mv);
            // 拦截器后置调用
            mappedHandler.applyPostHandle(processedRequest, response, mv);
          // 分发结果
          processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
      }
        ```
    ## 1 处理器 HandlerMapping
    
    
    
    
    请求分发完毕后就需要去进行处理,这就是我们本文所要讲的重点:HandlerMapping。如果使用过springmvc进行开发过的同学都知道,handler通常指的就是业务上我们在Controller层中编写的带有@RequestMapping的方法,在SpringBoot中为了方便开发,框架还提供了@GetMapping,@PostMaping等注解来简化配置。而这些所有方法为构成一个HandlerMapping。
    
    
    
    ## 2 如何转化HandlerMapping?
    
    
    
    我们目光可以聚焦到EnableWebMvcConfiguration#requestMappingHandlerMapping方法,它会去创建RequestMappingHandlerMapping对象(就是转化上面提到注解的类)。这个对象实现了InitializingBean接口,所以最终会调用其afterPropertiesSet方法:
    
    
    ```java
    @Override
      public void afterPropertiesSet() {
             // 初始化handler
        initHandlerMethods();
      }
      
    protected void initHandlerMethods() {
        for (String beanName : getCandidateBeanNames()) {
          if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            processCandidateBean(beanName);
          }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }
    

    其中的processCandidateBean会去解析带有@Controller注解的类。我们简单的看一下代码:

    if (beanType != null && isHandler(beanType)) {
          detectHandlerMethods(beanName);
        }
        
    @Override
      protected boolean isHandler(Class<?> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
            AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
    

    isHandler方法会找到带有@Controller注解或@RequestMapping的类,detectHandlerMethods方法会对整个类进行处理,解析带有@RequestMapping注解的方法并注册到MappingRegistry中去。

    3 如何注册HandlerMapping?

    最后看一下框架是怎么将handlers注册到控制器DispatcherServlet中去的。

    DispatcherServlet的父类中添加了一个ContextRefreshListener监听器,当容器完全启动后,会调用其onRefresh方法,而正是这个方法,去注册了handers。

    @Override
      protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
      }
    
      protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        // 注册handler
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
      }
    

    可以看到控制器初始化了非常多的东西,这里我们只关注initHandlerMappings方法,后面的文章会讲到

    initHandlerAdapters,initHandlerExceptionResolvers等。

    具体代码如下(省略部分代码):

    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
    
        if (this.detectAllHandlerMappings) { // true
          Map<String, HandlerMapping> matchingBeans =
              BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    
          this.handlerMappings = new ArrayList<>(matchingBeans.values());
        }
        else {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
    

    由以上代码可以知道,它会去Spring IOC容器中获取HandlerMapping类型的所有Bean设置为控制器的Handler,而上文说的RequestMappingHandlerMapping就是其中一个Bean。与此同时我们发现,也可以通过自己手写一个HandlerMapping实现类从而注册到控制器当中去。

    最后用流程图总结一下这个过程:


    image.png

    相关文章

      网友评论

        本文标题:SpringMVC详解-请求分发流程之处理器 HandlerMa

        本文链接:https://www.haomeiwen.com/subject/mvhcvktx.html