springmvc源码分析-HandlerMapping

HandlerMapping的作用便是根据http请求找到对应Controller的某个执行方法,springmvc默认的策略会提供3个实例,分别为RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、RouterFunctionMapping。现在的应用开发中,最常用的便是RequestMappingHandlerMapping,因此,本文来分析下RequestMappingHandlerMapping几个重要的属性

@Bean
@SuppressWarnings("deprecation")
public RequestMappingHandlerMapping requestMappingHandlerMapping(
        @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
        @Qualifier("mvcConversionService") FormattingConversionService conversionService,
        @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

    RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
    mapping.setOrder(0);
    mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
    mapping.setContentNegotiationManager(contentNegotiationManager);
    mapping.setCorsConfigurations(getCorsConfigurations());

    PathMatchConfigurer pathConfig = getPathMatchConfigurer();
    if (pathConfig.getPatternParser() != null) {
        mapping.setPatternParser(pathConfig.getPatternParser());
    }
    else {
        mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
        mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());

        Boolean useSuffixPatternMatch = pathConfig.isUseSuffixPatternMatch();
        if (useSuffixPatternMatch != null) {
            mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
        }
        Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
        if (useRegisteredSuffixPatternMatch != null) {
            mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
        }
    }
    Boolean useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
    if (useTrailingSlashMatch != null) {
        mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
    }
    if (pathConfig.getPathPrefixes() != null) {
        mapping.setPathPrefixes(pathConfig.getPathPrefixes());
    }

    return mapping;
}

首先就是设置order,值越小,越先执行。然后就是interceptor,这个也在应用程序中几乎是必用的,来看下springmvc如何添加的。

protected final Object[] getInterceptors(
            FormattingConversionService mvcConversionService,
            ResourceUrlProvider mvcResourceUrlProvider) {

    if (this.interceptors == null) {
        InterceptorRegistry registry = new InterceptorRegistry();
        addInterceptors(registry);
        registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
        registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
        this.interceptors = registry.getInterceptors();
    }
    return this.interceptors.toArray();
}

应用开发中,只需要实现addInterceptors方法,往InterceptorRegistry添加拦截器HandlerInterceptor,在内部会转化为InterceptorRegistration(registry维护这一个registration列表)。registration包含了拦截器对象和拦截器要拦截的路径信息。最后在真正的返回拦截器列表时,又会转化为MappedInterceptor(当有设置路径信息的情况下),没有路径信息返回的是handlerInterceptor对象本身。

当完成RequestMappingHandlerMapping对象的创建后,因为该对象还实现了InitializingBean接口,因此在spring bean的生命周期中还会调用afterPropertiesSet方法,这个方法是RequestMappingHandlerMapping的核心,因为在这个方法中要完成http请求路径和对应controller方法映射关系的逻辑处理

protected void initHandlerMethods() {
    for (String beanName : getCandidateBeanNames()) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            processCandidateBean(beanName);
        }
    }
}

这个方法中,循环处理容器的beanName列表,然后取出beanName对应的Class对象,判断该class对象是否为Handler,判断标准就是看类是否有注解了Controller或者RequestMapping,若有,则会处理该Class对象的Method方法

protected void detectHandlerMethods(Object handler) {
    Class handlerType = (handler instanceof String ?
            obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
        Class userType = ClassUtils.getUserClass(handlerType);
        Map methods = MethodIntrospector.selectMethods(userType,
                (MethodIntrospector.MetadataLookup) method -> {
                    try {
                        return getMappingForMethod(method, userType);
                    }
                    catch (Throwable ex) {
                        throw new IllegalStateException("Invalid mapping on handler class [" +
                                userType.getName() + "]: " + method, ex);
                    }
                });
        //....中间日志省略
        methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

这个方法主要作用是找到method对象,还有对应的RequestMappingInfo对象,顾名思义,这个对象封装的是@RequestMapping注解的相关属性信息,然后再将这些对象关系注册

获取method对象及其RequestMappingInfo对象,主要为selectMethods方法,方法的两个入参,一个是Class对象,另一个是获取method对应RequestMappingInfo的方法。

public static  Map selectMethods(Class targetType, final MetadataLookup metadataLookup) {
    final Map methodMap = new LinkedHashMap<>();
    Set> handlerTypes = new LinkedHashSet<>();
    Class specificHandlerType = null;
      //若当前Class对象是代理对象,那么拿到被代理类的Class对象
    if (!Proxy.isProxyClass(targetType)) {
        specificHandlerType = ClassUtils.getUserClass(targetType);
        handlerTypes.add(specificHandlerType);
    }
//获取接口的Class对象,并且循环处理每个Class
    handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));

    for (Class currentHandlerType : handlerTypes) {
        final Class targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);

        ReflectionUtils.doWithMethods(currentHandlerType, method -> {
//这里是因为方法可能是重写的,因此要拿到具体的方法对象
            Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
//拿到方法对应的RequestMappingInfo对象
            T result = metadataLookup.inspect(specificMethod);
            if (result != null) {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
//将method对象及对应的requestMappingInfo对象加入到map中,并返回
                    methodMap.put(specificMethod, result);
                }
            }
        }, ReflectionUtils.USER_DECLARED_METHODS);
    }
    return methodMap;
}

上述这个方法主要逻辑就是拿到要处理的Class对象及所实现的接口的Class对象,然后循环处理每个Class对象下的method方法,若method方法符合MethodFilter((method -> !method.isBridge() && !method.isSynthetic())),那么获取method对象对应的RequestMappingInfo对象,然后添加到map中,处理完所有的Class对象后,map返回。

method对象如何获取到RequestMappingInfo

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);
            }
            String prefix = getPathPrefix(handlerType);
            if (prefix != null) {
                info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
            }
        }
        return info;
    }

首先,method方法需要有@RequestMapping注解的,然后解析注解的相关属性信息,创建RequestMappingInfo对象,该对象内部有很多成员RequestCondition,condition对象最终维护@RequestMapping注解对应的属性值,如consumes对应ConsumesRequestCondition对象。

再接着,获取Class对象的RequestMappingInfo对象,然后,再合并method对象和Class对象的RequestMappingInfo对象

当获取到所有的映射关系后,将每个映射关系注册到handlermapping的registry中

methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            registerHandlerMethod(handler, invocableMethod, mapping);
 });
public void register(T mapping, Object handler, Method method) {
    this.readWriteLock.writeLock().lock();
    try {
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        validateMethodMapping(handlerMethod, mapping);

        Set directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
        for (String path : directPaths) {
            this.pathLookup.add(path, mapping);
        }

        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);
        }

        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            corsConfig.validateAllowCredentials();
            this.corsLookup.put(handlerMethod, corsConfig);
        }

        this.registry.put(mapping,
                new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}

registry的几个成员如下,其中T为RequestMappingInfo,也就是handlerMapping的http请求和controller执行方法的关系维护在registry成员中。

private final Map> registry = new HashMap<>();

private final MultiValueMap pathLookup = new LinkedMultiValueMap<>();

private final Map> nameLookup = new ConcurrentHashMap<>();

private final Map corsLookup = new ConcurrentHashMap<>();

当对所有的handler(注解了RequestMapping或者Controller的类)的所有注解了RequestMapping的方法解析生成对应的映射关系,RequestMappingInfo--HandlerMethod后,RequestMappingHandlerMapping的初始化方法afterPropertiesSet就处理完了。

你可能感兴趣的:(springmvc源码分析-HandlerMapping)