SpringMVC源码分析(四)--BeanNameUrlHandlerMapping

1.BeanNameUrlHandlerMapping作用

BeanNameUrlHandlerMapping作用是将以/开头的beanName认为是请求url,通过访问url找到对应的bean,执行其内部的处理方法

使用示例:创建类继承Controller接口并添加@Controller("/controller")注解,@Controller注解中的value必须以/开头,配置类及测试代码参考前文SpringMVC源码分析(一)--基本组件

@Controller("/test02")
public class Controller02 implements org.springframework.web.servlet.mvc.Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.getWriter().print("hello test02");
        return null;
    }
}

浏览器访问http://127.0.0.1:8080/test02,页面即可响应hello test02文本

2.BeanNameUrlHandlerMapping注册处理器

BeanNameUrlHandlerMapping间接实现了ApplicationContextAware接口,初始化时会调用ApplicationObjectSupport#setApplicationContext

public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
    if (context == null && !this.isContextRequired()) {
        this.applicationContext = null;
        this.messageSourceAccessor = null;
    } else if (this.applicationContext == null) {
        if (!this.requiredContextClass().isInstance(context)) {
            throw new ApplicationContextException("Invalid application context: needs to be of type [" + this.requiredContextClass().getName() + "]");
        }
        this.applicationContext = context;
        this.messageSourceAccessor = new MessageSourceAccessor(context);
        // 初始化
        this.initApplicationContext(context);
    } else if (this.applicationContext != context) {
        throw new ApplicationContextException("Cannot reinitialize with different application context: current one is [" + this.applicationContext + "], passed-in one is [" + context + "]");
    }
}

protected void initApplicationContext(ApplicationContext context) throws BeansException {
    // 调用子类的初始化方法
    this.initApplicationContext();
}

protected void initApplicationContext() throws BeansException {}

initApplicationContext调用的是AbstractDetectingUrlHandlerMapping#initApplicationContext

public void initApplicationContext() throws ApplicationContextException {
    // 1.调用父类AbstractHandlerMapping#initApplicationContext
    super.initApplicationContext();
    // 2.检测处理器方法
    detectHandlers();
}

在AbstractDetectingUrlHandlerMapping#initApplicationContext中首先调用父类的initApplicationContext,目的是初始化interceptors,这部分可以通过子类继承扩展

protected void initApplicationContext() throws BeansException {
    extendInterceptors(this.interceptors);
    detectMappedInterceptors(this.adaptedInterceptors);
    initInterceptors();
}

protected void extendInterceptors(List<Object> interceptors) {}

protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
    // 查找容器中的MappedInterceptor,加入到adaptedInterceptors集合中
    mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(
        obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

protected void initInterceptors() {
    if (!this.interceptors.isEmpty()) {
        for (int i = 0; i < this.interceptors.size(); i++) {
            Object interceptor = this.interceptors.get(i);
            if (interceptor == null) {
                throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
            }
            // 将interceptor适配成HandlerInterceptor,加入到adaptedInterceptors集合中
            this.adaptedInterceptors.add(adaptInterceptor(interceptor));
        }
    }
}

添加完HandlerInterceptor之后,调用detectHandlers,寻找处理器方法

protected void detectHandlers() throws BeansException {
    ApplicationContext applicationContext = obtainApplicationContext();
    // detectHandlersInAncestorContexts表示是否在父容器中寻找
    // true表示在父容器和当前容器中查找所有bean,false表示只查找当前容器中的bean
    String[] beanNames = (this.detectHandlersInAncestorContexts ?
                          BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
                          applicationContext.getBeanNamesForType(Object.class));
    
    for (String beanName : beanNames) {
        // 检查beanName是否满足,抽象方法由BeanNameUrlHandlerMapping实现
        String[] urls = determineUrlsForHandler(beanName);
        if (!ObjectUtils.isEmpty(urls)) {
            // 如果找到了,注册处理器
            registerHandler(urls, beanName);
        }
    }
    
    if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
        logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
    }
}

protected abstract String[] determineUrlsForHandler(String beanName);

determineUrlsForHandler用于判断beanName是否以/开头,如果满足条件则会认为找到了控制器类

protected String[] determineUrlsForHandler(String beanName) {
    List<String> urls = new ArrayList<>();
    // 如果beanName以/开头就满足条件
    if (beanName.startsWith("/")) {
        urls.add(beanName);
    }
    // 或者beanName的别名以/开头也满足条件
    String[] aliases = obtainApplicationContext().getAliases(beanName);
    for (String alias : aliases) {
        if (alias.startsWith("/")) {
            urls.add(alias);
        }
    }
    return StringUtils.toStringArray(urls);
}

探测到控制器类之后就需要注册其中的请求处理方法,即调用AbstractUrlHandlerMapping#registerHandler

protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
    Assert.notNull(urlPaths, "URL path array must not be null");
    for (String urlPath : urlPaths) {
        registerHandler(urlPath, beanName);
    }
}

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;

    // 如果handler的类型是string,并且不是懒加载的,从Spring容器中根据类名获取处理器bean
    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 {
        // 1.如果路径就是/,则设置为rootHandler
        if (urlPath.equals("/")) {
            if (logger.isTraceEnabled()) {
                logger.trace("Root mapping to " + getHandlerDescription(handler));
            }
            setRootHandler(resolvedHandler);
        }
            // 2.如果路径就是/*,则设置为defaultHandler
        else if (urlPath.equals("/*")) {
            if (logger.isTraceEnabled()) {
                logger.trace("Default mapping to " + getHandlerDescription(handler));
            }
            setDefaultHandler(resolvedHandler);
        }
            // 3.否则将路径-控制器类添加到handlerMap中
        else {
            this.handlerMap.put(urlPath, resolvedHandler);
            if (logger.isTraceEnabled()) {
                logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
            }
        }
    }
}

至此BeanNameUrlHandlerMapping初始化完成

3.BeanNameUrlHandlerMapping获取处理器

当DispatcherServlet接收到请求时,与前文所述RequestMappingHandlerMapping一样,会在doDispatch方法中调用getHandler遍历每个HanderMapping去获取对应的处理器,源码见DispatcherServlet#getHandler

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        // 遍历每个HanderMapping
        for (HandlerMapping mapping : this.handlerMappings) {
            // 获取处理器对象
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

假设请求是http://127.0.0.1:8080/test02,则通过BeanNameUrlHandlerMapping能够匹配到对应的处理器方法

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 抽象方法,由具体的实现类处理,这里调用AbstractUrlHandlerMapping#getHandlerInternal
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        // 如果没有找到,则获取默认处理器,即匹配上文中注册/*的处理器
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // handler如果是string,则根据类名从容器中获取bean
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    // 封装成HandlerExecutionChain,其中包含Handler及HandlerInterceptor
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }

    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

AbstractUrlHandlerMapping#getHandlerInternal源码如下:

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    // 获取请求的路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    // 查找Handler
    Object handler = lookupHandler(lookupPath, request);
    // 如果没有找到Handler
    if (handler == null) {
        Object rawHandler = null;
        // 如果路径就是/,则返回rootHandler
        if (StringUtils.matchesCharacter(lookupPath, '/')) {
            rawHandler = getRootHandler();
        }
        // 仍然为null,则返回defaultHandler
        if (rawHandler == null) {
            rawHandler = getDefaultHandler();
        }
        if (rawHandler != null) {
            // 如果是string类型,则从容器中根据类名获取bean
            if (rawHandler instanceof String) {
                String handlerName = (String) rawHandler;
                rawHandler = obtainApplicationContext().getBean(handlerName);
            }
            validateHandler(rawHandler, request);
            // 封装成HandlerExecutionChain
            handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
        }
    }
    return handler;
}

protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
                                          String pathWithinMapping, @Nullable Map<String, String> uriTemplateVariables) {
    HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
    chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
    if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
        chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
    }
    return chain;
}

根据路径查找方法处理器的核心逻辑如下:

protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    // 直接根据url从handlerMap中查找
    Object handler = this.handlerMap.get(urlPath);
    if (handler != null) {
        // 如果查找到了直接返回
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }
        validateHandler(handler, request);
        return buildPathExposingHandler(handler, urlPath, urlPath, null);
    }

    // 通过正则匹配查找最符合的处理器
    // 添加路径表达式到matchingPatterns
    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.isTraceEnabled() && matchingPatterns.size() > 1) {
            logger.trace("Matching patterns " + matchingPatterns);
        }
        // 获取最佳匹配的路径
        bestMatch = matchingPatterns.get(0);
    }
    if (bestMatch != null) {
        // 获取最佳匹配的Handler
        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 + "]");
            }
        }
        // 如果是string,从Spring容器中根据类名获取bean
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }
        validateHandler(handler, request);
        String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);

        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.isTraceEnabled() && uriTemplateVariables.size() > 0) {
            logger.trace("URI variables " + uriTemplateVariables);
        }
        return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
    }

    return null;
}

最后将HandlerExecutionChain对象交给HandlerAdapter去执行,这里BeanNameUrlHandlerMapping匹配的是SimpleControllerHandlerAdapter,它会执行handle方法调用自定义控制器中重写的handle方法处理请求

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    // 是否支持此handler,显然是支持的,因为我们定义的/controller实现了mvc包中的Controller接口
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
        // 调用我们控制器中重写的handle方法处理请求
		return ((Controller) handler).handleRequest(request, response);
	}

    // 省略其他代码...
}

请求的执行过程将在HandlerAdapter篇章中详述

  • 23
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lm_ylj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值