Skip to content

Latest commit

 

History

History
168 lines (164 loc) · 6.84 KB

2019-05-17-handlerMapping.md

File metadata and controls

168 lines (164 loc) · 6.84 KB
layout title no-post-nav category tags description
post
SpringMvc初始化handlerMapping(二)
true
arch
arch
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进行匹配相关信息。 后续会有相关介绍,请等待下文。