SpringBoot MVC(3)映射的匹配

684 阅读2分钟

dispatcherServlet初始化完成之后,调用service方法,它是MVC处理url的入口,实际执行父类HttpServlet下的service方法

映射的匹配

HttpServlet->service():
    // 获取请求类型
    String method = req.getMethod();
    if (method.equals(METHOD_GET)) {
        // 不同的请求类型执行的过程不一样,这里仅以get方法为例
        doGet(req, resp);
    }
FrameworkServlet->doGet():
    processRequest(request, response);
DispatcherServlet->doService():
    // 前面有一系列将初始化过程中的变量赋到request的attributes属性以及绑定线程变量的过程
    doDispatch(request, response);
DispatcherServlet->doDispatch():
    // 确定处理执行链
    mappedHandler = getHandler(processedRequest);
DispatcherServlet->getHandler():
    // 这里的handlerMappings就是上篇中的四个,以下主要讲述RequestMappingHandlerMapping
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;	
AbstractHandlerMapping->getHandler():
    Object handler = getHandlerInternal(request);	
AbstractHandlerMethodMapping->getHandlerInternal():
    HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
AbstractHandlerMethodMapping->lookupHandlerMethod():
    List<Match> matches = new ArrayList<>();
    // 这里的lookupPath就是请求的url,从urlLookup中获取key完全匹配的
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        // 如果不为空的话,判断其它的信息是否符合,将符合的添加到matches变量中	
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // 如果为空的话,从mappingLookup中查找所有信息是否有符合的
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }
    if (!matches.isEmpty()) {
        // 如果匹配多个的话,会根据相关的算法找到最合适的那个,然后返回它的处理方法
        // requestMappingInfo的排序参见它的compareTo方法
        ......
    } 
    else {
        // 如果没有匹配的话,会直接根据名字找一次
        // 如果找到的话,会对比其他信息,只要有不符合的就会抛出异常
        // 如果没有找到,直接返回null
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }

DispatcherServlet->getHandler()方法中,按照RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping、WelcomePageHandlerMapping的顺序尝试获取执行链,找到直接返回,为空则进入下一个HandlerMapping的尝试,SimpleUrlHandlerMapping的匹配路径是/**,因此最极端情况是返回它的执行链

路径匹配规则

  • /a/b 匹配/a/b
  • /a/** 匹配/a或者/a/ + 任意字符
  • /a/{id} 匹配/a/ + 任意字符(/除外)
  • /a/* 匹配/a/ + 任意字符(/除外)
  • /a/? 匹配/a/ + 任意一个字符(/除外)

@RequestMapping属性值

  • value/path 指定url
  • method 指定请求的method类型,如GET,POST,PUT,DELETE等
  • params 指定request中必须包含的参数值
  • headers 指定header中必须包含的参数值
  • consumes 指定header中的提交内容类型Content-Type,如application/json, text/html等
  • produces 指定返回的内容类型Accept,如application/json,text/html等

只有当请求与@RequestMapping属性值完全符合的时候,才会添加到matches变量中,最终返回它所对应的处理方法