SpringMVC源码解析三(处理映射器HandlerMapping的解析)

HandlerMapping继承关系图:

1.BeanNameUrlHandlerMapping

配置文件中配置controller的bean,且bean的id必须以“/”开头,id就是controller可以处理的url

<bean id = "/hello" class="com.liyao.controller.HelloController"/>

2.SimpleUrlHandlerMapping

需要在配置文件中配置controller的bean以及mapping

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hi">hi</prop>
            </props>
        </property>
    </bean>
<bean id = "hi" class="com.lic.controller.HiController"/>

3.RequestMappingUrlHandlerMapping

基于@RequestMapping注解对应映射

AbstractUrlHandlerMapping 映射器映射出来的是 handler 是 Controller 对象, 也就是类级别的处理器

AbstractHandlerMethodMapping 映射器映射出来的 handler 是 HandlerMethod 对象, 也就是方法级别的处理器

DispatcherServlet#getHandler()方法实现:

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        //遍历所有HandlerMapping, 获取适合当前请求的映射处理器
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
            /**
             * 1.遍历所有的HandlerMapping,根据Request获取到合适的HandlerMapping
             * 2.利用HandlerMapping通过请求信息获取Handler处理器并包装为HandlerExecutionChain执行链
             *
             * {@link AbstractHandlerMapping#getHandler(HttpServletRequest)}
             * hm  ==>  RequestMappingInfoHandlerMapping
             */
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

分析

  1. 遍历所有的注册HandlerMapping,根据Request获取到合适的HandlerMapping
  2. 利用HandlerMapping通过请求信息获取Handler处理器并包装为HandlerExecutionChain执行链返回

AbstractHandlerMapping#getHandler()方法实现:

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    /**
     * 由子类实现, 根据请求信息获取指定的Handler
     * {@link AbstractHandlerMethodMapping#getHandlerInternal(HttpServletRequest)}
         * {@link AbstractUrlHandlerMapping#getHandlerInternal(javax.servlet.http.HttpServletRequest)}
     */
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    if (handler instanceof String) {
        String handlerName = (String) handler;
        //从容器中获取Handler
        handler = obtainApplicationContext().getBean(handlerName);
    }
    /**
     * 将handler和request包装为HandlerExecutionChain,在HandlerExecutionChain设置了相关过滤器
     */
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
}

分析:

  1. AbstractHandlerMapping子类中根据请求信息获取指定的Handler
  2. 如果获取的handler是一个String类型的名称, 则从容器中获取handler实例
  3. 将handler和request包装为HandlerExecutionChain,在HandlerExecutionChain设置了相关过滤器

1. AbstractHandlerMapping子类一: AbstractHandlerMethodMapping

AbstractHandlerMethodMapping#getHandlerInternal()方法实现:

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //lookupPath为请求路径信息
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    if (logger.isDebugEnabled()) {
        logger.debug("Looking up handler method for path " + lookupPath);
    }
    this.mappingRegistry.acquireReadLock();  //获取读锁
    try {
        /**
         * 1. 获取HandlerMethod实例(不健全, 数据没有封装完成)
         */
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        if (logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }
        /**
         * 2. 重塑HandlerMethod实例  ==> 重点
         */
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

分析:

  1. 根据请求信息获取HandlerMethod实例
  2. 封装HandlerMethod实例

(1). AbstractHandlerMethodMapping#lookupHandlerMethod()方法实现:

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    /**
      * 由映射处理器映射出对应的MappingInfo信息, 可能获取多个
      */
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        /**
         * 将HandlerMethod实例与Request进行包装, 添加到matches集合中
         */
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // No choice but to go through all mappings...
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    if (!matches.isEmpty()) {
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        //对所有符合条件的处理器进行排序
        matches.sort(comparator);
        if (logger.isTraceEnabled()) {
            logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
        }
        /**
         * 获取matches集合中最合适的处理器
         */
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
                        request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
            }
        }
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        /**
         * {@link RequestMappingInfoHandlerMapping#handleMatch(org.springframework.web.servlet.mvc.method.RequestMappingInfo, String, HttpServletRequest)}
         */
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

分析: 

  1. 根据url从注册中心获取对应的MappingInfo信息,封装到directPathMatches集合中
  2. 将HandlerMethod实例与Request进行包装, 并且创建Match实例, 在该实例中封装了HandlerMethod方法
  3. 由映射处理器(RequestMappingInfoHandlerMapping) 映射出对应的handler

AbstractHandlerMethodMapping#addMatchingMappings()方法实现:

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
    for (T mapping : mappings) {
        T match = getMatchingMapping(mapping, request);
        if (match != null) {
            /**
             * 根据请求路径从mappingLookup集合中获取处理方法, 将Method封装到Match实例中
             * 后面处理请求时会利用反射执行该方法
             */
            matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
        }
    }
}

(2) HandlerMethod#createWithResolvedBean()方法实现:

public HandlerMethod createWithResolvedBean() {
    Object handler = this.bean;
    if (this.bean instanceof String) {  //如果bean不是实例而是一个BeanName,则从工厂中获取该bean实例
        Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
        String beanName = (String) this.bean;
        // 从工厂中获取bean
        handler = this.beanFactory.getBean(beanName);
    }
    /**
     * 问题: 这里为什么要重新创建一个HandlerMethod实例,而不是在原有的HandlerMethod实例上进行修改?
     */
    return new HandlerMethod(this, handler);
}

private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
    Assert.notNull(handlerMethod, "HandlerMethod is required");
    Assert.notNull(handler, "Handler object is required");
    this.bean = handler;  //反射执行Method时需要传入实例对象
    this.beanFactory = handlerMethod.beanFactory;
    this.beanType = handlerMethod.beanType;
    this.method = handlerMethod.method;
    this.bridgedMethod = handlerMethod.bridgedMethod;
    this.parameters = handlerMethod.parameters;
    this.responseStatus = handlerMethod.responseStatus;
    this.responseStatusReason = handlerMethod.responseStatusReason;
    this.resolvedFromHandlerMethod = handlerMethod;
}

这里有一个疑问: 为什么要重新创建一个HandlerMethod实例,而不是在原有的HandlerMethod实例上进行修改? 

1.1 AbstractHandlerMethodMapping子类: RequestMappingInfoHandlerMapping

在容器初始化过程中创建映射器(RequestMappingHandlerMapping)对象时,会寻找所有被@Controller 注解类中被 @RequestMapping 注解的方法,然后解析方法上的 @RequestMapping 注解,把解析结果封装成 RequestMappingInfo 对象,也就是说RequestMappingInfo 对象是用来装载方法的匹配相关信息,每个匹配的方法都会对应一个 RequestMappingInfo 对象

RequestMappingInfoHandlerMapping#handleMatch()方法实现: 

@Override
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
    super.handleMatch(info, lookupPath, request);

    String bestPattern;
    Map<String, String> uriVariables;

    Set<String> patterns = info.getPatternsCondition().getPatterns();
    if (patterns.isEmpty()) {
        bestPattern = lookupPath;
        uriVariables = Collections.emptyMap();
    }
    else {
        bestPattern = patterns.iterator().next();
        uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
    }

    request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);

    if (isMatrixVariableContentAvailable()) {
        Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);
        request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
    }

    Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
    request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);

    if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
        Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
        request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
    }
}

MappingRegistry#getMappingsByUrl()方法实现:

@Nullable
public List<T> getMappingsByUrl(String urlPath) {
    return this.urlLookup.get(urlPath);
}

由此可知, 在初始化SpringMVC时处理器已经注册到urlLookup集合中, key为url, 在MappingRegistry#register()方法中实现了对处理器的注册

AbstractHandlerMethodMapping.MappingRegistry#register()方法实现

public void register(T mapping, Object handler, Method method) {
    this.readWriteLock.writeLock().lock();
    try {
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        assertUniqueMethodMapping(handlerMethod, mapping);
        /**
         * mappingLookup: 维护请求信息(RequestMappingInfo)与HandlerMethod的映射关系
         */
        this.mappingLookup.put(mapping, handlerMethod);

        if (logger.isInfoEnabled()) {
            logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
        }

        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            /**
             * urlLookup: 维护url与请求信息(RequestMappingInfo)的映射关系
             * 后面会根据Url找RequestMappingInfo, 再根据RequestMappingInfo找HandlerMethod对请求进行处理
             */    
            this.urlLookup.add(url, mapping);
        }

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

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

        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}

在this.urlLookup.add(url, mapping) 处添加断点查看调用栈:

分析:

  1. 模块1主要逻辑为创建以及配置Web应用上下文(WebApplicationContext)
  2. 模块2主要逻辑为springMVC相关bean对象注册解析, 即WebApplicationContext的实例化
  3. 模块3主要逻辑为遍历所有Controller类, 对类中定义的所有处理方法进行注册,即注册Handler处理器

模块3逻辑分析:

RequestMappingInfoHandlerMapping类实现了InitializingBean接口并重写了afterPropertiesSet(), 在调用初始化方法时, 会触发afterPropertiesSet()方法, 将启动对处理器(handler)的探测以及注册

AbstractHandlerMethodMapping#afterPropertiesSet()方法实现:

@Override
public void afterPropertiesSet() {
    //初始化Handler方法, 就是对编写的Control层方法进行注册, key为方法的访问路径, value为对方法的包装类HandlerMethod
    initHandlerMethods();
}

protected void initHandlerMethods() {
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for request mappings in application context: " + getApplicationContext());
    }
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
            obtainApplicationContext().getBeanNamesForType(Object.class));

    for (String beanName : beanNames) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            Class<?> beanType = null;
            try {
                //获取对应bean的Class
                beanType = obtainApplicationContext().getType(beanName);
            }
            catch (Throwable ex) {
                // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                }
            }
            /**
             * isHandler()方法用来判断是否符合注册条件, 具体的判断逻辑由子类实现
             */
            if (beanType != null && isHandler(beanType)) {
                //对Controller类中所有的方法进行探测
                detectHandlerMethods(beanName);
            }
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}

AbstractHandlerMethodMapping#detectHandlerMethods()方法实现:

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<Method, T> methods = MethodIntrospector.selectMethods(userType,
                (MethodIntrospector.MetadataLookup<T>) method -> {
                    try {
                        return getMappingForMethod(method, userType);
                    }
                    catch (Throwable ex) {
                        throw new IllegalStateException("Invalid mapping on handler class [" +
                                userType.getName() + "]: " + method, ex);
                    }
                });
        if (logger.isDebugEnabled()) {
            logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
        }
        methods.forEach((method, mapping) -> {
            /**
             * 循环遍历所有的方法,进行注册
             * handler为controller类实例, 每一个HandlerMethod中都维护着该实例, 因为在后面执行该方法时需要传入该实例
             */
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

 

2.AbstractHandlerMapping子类二: AbstractUrlHandlerMapping

AbstractUrlHandlerMapping#getHandlerInternal()方法实现:

@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    //获取请求路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    /**
     * 根据请求路径获取handler
     */
    Object handler = lookupHandler(lookupPath, request);
    if (handler == null) {
        // We need to care for the default handler directly, since we need to
        // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
        Object rawHandler = null;
        if ("/".equals(lookupPath)) {
            rawHandler = getRootHandler();
        }
        if (rawHandler == null) {
            rawHandler = getDefaultHandler();
        }
        if (rawHandler != null) {
            // Bean name or resolved handler?
            if (rawHandler instanceof String) {
                String handlerName = (String) rawHandler;
                rawHandler = obtainApplicationContext().getBean(handlerName);
            }
            validateHandler(rawHandler, request);
            handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
        }
    }
    if (handler != null && logger.isDebugEnabled()) {
        logger.debug("Mapping [" + lookupPath + "] to " + handler);
    }
    else if (handler == null && logger.isTraceEnabled()) {
        logger.trace("No handler mapping found for [" + lookupPath + "]");
    }
    return handler;
}

AbstractUrlHandlerMapping#lookupHandler()方法实现:

@Nullable
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    //尝试直接匹配
    Object handler = this.handlerMap.get(urlPath);
    if (handler != null) {
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }
        validateHandler(handler, request);
        return buildPathExposingHandler(handler, urlPath, urlPath, null);
    }

    //尝试模式匹配
    List<String> matchingPatterns = new ArrayList<>();
    for (String registeredPattern : this.handlerMap.keySet()) {
        if (getPathMatcher().match(registeredPattern, urlPath)) {
            matchingPatterns.add(registeredPattern);
        }
        else if (useTrailingSlashMatch()) {
            if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
                matchingPatterns.add(registeredPattern + "/");
            }
        }
    }

    String bestMatch = null;
    Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
    if (!matchingPatterns.isEmpty()) {
        matchingPatterns.sort(patternComparator);
        if (logger.isDebugEnabled()) {
            logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
        }
        bestMatch = matchingPatterns.get(0);
    }
    if (bestMatch != null) {
        handler = this.handlerMap.get(bestMatch);
        if (handler == null) {
            if (bestMatch.endsWith("/")) {
                handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
            }
            if (handler == null) {
                throw new IllegalStateException(
                        "Could not find handler for best pattern match [" + bestMatch + "]");
            }
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }
        validateHandler(handler, request);
        String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);

        // There might be multiple 'best patterns', let's make sure we have the correct URI template variables
        // for all of them
        Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
        for (String matchingPattern : matchingPatterns) {
            if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
                Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
                Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
                uriTemplateVariables.putAll(decodedVars);
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
        }
        return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
    }

    // No handler found...
    return null;
}

在上面方法中都是通过handlerMap获取指定handler, 那么接下来就看下怎么将handler对象加入handlerMap集合中

AbstractUrlHandlerMapping#registerHandler()方法实现:

protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
    Assert.notNull(urlPath, "URL path must not be null");
    Assert.notNull(handler, "Handler object must not be null");
    Object resolvedHandler = handler;

    // Eagerly resolve handler if referencing singleton via name.
    if (!this.lazyInitHandlers && handler instanceof String) {
        String handlerName = (String) handler;
        ApplicationContext applicationContext = obtainApplicationContext();
        if (applicationContext.isSingleton(handlerName)) {
            resolvedHandler = applicationContext.getBean(handlerName);
        }
    }

    Object mappedHandler = this.handlerMap.get(urlPath);
    if (mappedHandler != null) {
        if (mappedHandler != resolvedHandler) {
            throw new IllegalStateException(
                    "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
                    "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
        }
    }
    else {
        if (urlPath.equals("/")) {
            if (logger.isInfoEnabled()) {
                logger.info("Root mapping to " + getHandlerDescription(handler));
            }
            setRootHandler(resolvedHandler);
        }
        else if (urlPath.equals("/*")) {
            if (logger.isInfoEnabled()) {
                logger.info("Default mapping to " + getHandlerDescription(handler));
            }
            setDefaultHandler(resolvedHandler);
        }
        else {
            /**
             * 此处完成了对Handler的注册
             */
            this.handlerMap.put(urlPath, resolvedHandler);
            if (logger.isInfoEnabled()) {
                logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
            }
        }
    }
}

在AbstractUrlHandlerMapping#registerHandler()方法中完成了对handler的注册

查看该方法的调用栈:

通过调用栈可知, 是在子类中调用父类AbstractUrlHandlerMapping的registerHandler()方法

 

2.1 AbstractUrlHandlerMapping子类一: SimpleUrlHandlerMapping

SimpleUrlHandlerMapping#registerHandlers()方法实现:

protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
    if (urlMap.isEmpty()) {
        logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
    }
    else {
        urlMap.forEach((url, handler) -> {
            // Prepend with slash if not already present.
            if (!url.startsWith("/")) {
                url = "/" + url;
            }
            // Remove whitespace from handler bean name.
            if (handler instanceof String) {
                handler = ((String) handler).trim();
            }
            registerHandler(url, handler);
        });
    }
}

在SimpleUrlHandlerMapping#registerHandlers(Map<String, Object> urlMap)中调用了SimpleUrlHandlerMapping#registerHandlers(

String urlPath, Object handler)方法

SimpleUrlHandlerMapping#initApplicationContext()方法实现:

@Override
public void initApplicationContext() throws BeansException {
       /**
     * 其顶级父类AbstractHandlerMapping继承了WebApplicationObjectSupport,容器初始化时会自动调用模板方法
     * initApplicationContext, 这里子类重写该方法并加了一些逻辑, 主要是为了将匹配该映射器的Handler对象加入
     * 到handlerMap集合中
     */
    super.initApplicationContext();
    registerHandlers(this.urlMap);
}

protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
    if (urlMap.isEmpty()) {
        logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
    }
    else {
        urlMap.forEach((url, handler) -> {
            // Prepend with slash if not already present.
            if (!url.startsWith("/")) {
                url = "/" + url;
            }
            // Remove whitespace from handler bean name.
            if (handler instanceof String) {
                handler = ((String) handler).trim();
            }
            registerHandler(url, handler);
        });
    }
}

 

2.2 AbstractUrlHandlerMapping子类二: BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping中没有registerHandlers()方法, 而是由其父类AbstractUrlHandlerMapping进行实现

AbstractDetectingUrlHandlerMapping#initApplicationContext()方法实现:

@Override
public void initApplicationContext() throws ApplicationContextException {
    /**
     * 其顶级父类AbstractHandlerMapping继承了WebApplicationObjectSupport,容器初始化时会自动调用模板方法
     * initApplicationContext, 这里子类重写该方法并加了一些逻辑, 主要是为了将匹配该映射器的Handler对象加入
     * 到handlerMap集合中
     */
    super.initApplicationContext();
    detectHandlers();
}
protected void detectHandlers() throws BeansException {
    ApplicationContext applicationContext = obtainApplicationContext();
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for URL mappings in application context: " + applicationContext);
    }
    /**
     * 将SpringMVC容器中注册的Bean的name都找出来放进数组中
     */
    String[] beanNames = (this.detectHandlersInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
            applicationContext.getBeanNamesForType(Object.class));

    // Take any bean name that we can determine URLs for.
    for (String beanName : beanNames) {
        /**
         * 匹配到符合该映射器的bean的name
         */
        String[] urls = determineUrlsForHandler(beanName);
        if (!ObjectUtils.isEmpty(urls)) {
            /**
             * 调用父类(AbstractUrlHandlerMapping)的registerHandler方法将匹配的beanName和urls分别作为key和value
             * 装进handlerMap集合中
             */
            registerHandler(urls, beanName);
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
            }
        }
    }
}

BeanNameUrlHandlerMapping#determineUrlsForHandler方法实现:

@Override
protected String[] determineUrlsForHandler(String beanName) {
    List<String> urls = new ArrayList<>();
    if (beanName.startsWith("/")) {
        urls.add(beanName);
    }
    String[] aliases = obtainApplicationContext().getAliases(beanName);
    for (String alias : aliases) {
        if (alias.startsWith("/")) {
            urls.add(alias);
        }
    }
    return StringUtils.toStringArray(urls);
}

至此, 处理器的获取解析完成;

 

相关文章:

     SpringMVC源码解析一(在Spring源码项目中搭建SpringMVC源码模块)

     SpringMVC源码解析二(请求过程解析)

     SpringMVC源码解析三(处理映射器HandlerMapping的解析)

     SpringMVC源码解析四(处理适配器HandlerAdapter的解析)

     SpringMVC源码解析五(HandlerMethod执行过程解析)

     SpringMVC源码解析六(ModelAndView解析)

     SpringMVC源码解析七(初始化过程解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值