【SpringMvc执行流程】SpringMvc初始化handlerMapping(二)

前面我们分析了spring如何接入Servlet,执行onRefresh方法,而HandlerMapping的初始化就在OnRefresh中调用。

    protected void onRefresh(ApplicationContext context) {
        System.out.println("=======dispatherServlet onfresh");
        initStrategies(context);
    }

initStrategies方法是所有初始化的集合

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

这里我们只关注initHandlerMappings(context)

private void initHandlerMappings(ApplicationContext context) {
  this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}

我们忽略其他直接看重点getDefaultStrategies,此函数是加载所有的HandlerMapping.class.

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();
    String value = defaultStrategies.getProperty(key);
    for (String className : classNames) {
            Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
            Object strategy = createDefaultStrategy(context, clazz); 
    }
}
  • defaultStrategies.getProperty(key)是通过加载DispatcherServlet同级目录下的DispatcherServlet.properties文件,获取需要执行的实现类。properties文件内容如下

    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

    由文件内容可知获取后类是BeanNameUrlHandlerMappingRequestMappingHandlerMapping.

  • createDefaultStrategy对获取后的class进行进行bean实例化。

    protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
     return context.getAutowireCapableBeanFactory().createBean(clazz);
    }

    实例化时,我们可以注意到一个细节是InitializingBean类的中的afterPropertiesSet方法回调。

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
         throws Throwable {
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        ((InitializingBean) bean).afterPropertiesSet();
        }   
    }

    BeanNameUrlHandlerMappingRequestMappingHandlerMapping中,只有RequestMappingHandlerMapping满足afterPropertiesSet。也正是我们想要的执行回调。

    @Override
    public void afterPropertiesSet() {
     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();
    }
  • useSuffixPatternMatch 默认为true,作用是匹配url.*

  • useTrailingSlashMatch 默认为true, 作用是尾部加上/

重点在super.afterPropertiesSet();

@Override
public void afterPropertiesSet() {
    initHandlerMethods();
}

回调的目的是初始化所有的方法HandlerMethods

protected void initHandlerMethods() {
    for (String beanName : beanNames) {
        if (beanType != null && isHandler(beanType)) {
            detectHandlerMethods(beanName);
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}
  • isHandler方法时对bean类型进行判断

    @Override
    protected boolean isHandler(Class<?> beanType) {
      return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
              AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
  • detectHandlerMethods是对满足条件的bean进行处理。

    protected void detectHandlerMethods(final Object handler) {
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
              (MethodIntrospector.MetadataLookup<T>) method -> {
                      return getMappingForMethod(method, userType);
                      } //处理类中所有的方法
          methods.forEach((method, mapping) -> {
              Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
              registerHandlerMethod(handler, invocableMethod, mapping);//把每个处理过后的method,和处理时的相关信息mapping保存
          });
      }
    }

    下面看下spring如何对method进行处理的。

    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
      RequestMappingInfo info = createRequestMappingInfo(method);
      if (info != null) {
          RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
          if (typeInfo != null) {
              info = typeInfo.combine(info);
          }
      }
      return info;
    }

    原来spring创建了一个RequestMappingInfo来保存method相关信息。具体什么信息,跟踪到createRequestMappingInfo中。

    protected RequestMappingInfo createRequestMappingInfo(
          RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
    
      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);
      }
      return builder.options(this.config).build();
    }

    原来是储存@RequestMapping注解的信息,如常用的value=hello

  • 再回到detectHandlerMethods方法,看下registerHandlerMethod方法

    protected void registerHandlerMethod(Object handler, Method method, T mapping) {
      this.mappingRegistry.register(mapping, handler, method);
    }

    发现spring用一个名为mappingRegistry类,存储mapping,handler和method。
    到此initHandlerMapping就完成了所有操作。那我们发挥自己的想象,当请求来时,一定会来mappingRegistry进行匹配相关信息。
    后续会有相关介绍,请等待下文。


文章作者: Ciwei
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ciwei !
 上一篇
【SpringMvc执行流程】SpringMvc中RequestCondition的作用(三) 【SpringMvc执行流程】SpringMvc中RequestCondition的作用(三)
初始化springmvc初始化时,会回调RequestMappingHandlerMapping中的afterPropertiesSet方法。 @Override public void afterPropertiesSet() {
2019-07-20
下一篇 
【SpringMvc执行流程】SpringMvc从Servlet到DispatcherServlet(一) 【SpringMvc执行流程】SpringMvc从Servlet到DispatcherServlet(一)
DispatcherServlet最主要的功能函数是onRefresh 和 doService。 onRefresh @Override protected void onRefresh(ApplicationContext cont
2019-07-20
  目录