[Turn] explains how SpringMVC when the request is to find the right Controller [with source code analysis]

table of Contents

Foreword

SpringMVC is one of the mainstream Web MVC framework. 

If some students are not familiar with it, then please refer to its entry Blog: http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html

We use the browser via the address http: // ip: port / contextPath / path access, how SpringMVC is that in the end user is in the access method which Controller, in the end what happened during this period.

This paper will analyze SpringMVC how to deal with the mapping between the request and the Controller, so readers know this process in the end what happened.

Source code analysis

Before analyzing the source code, we first look at a few things.

1. This process is an important interfaces and classes.

HandlerMethod categories:

  Introduced after Spring3.1 version. Is a method of encapsulating a parameter annotation method, class method returns the value of many other elements.

  

  InvocableHandlerMethod its subclasses has two important properties WebDataBinderFactory and HandlerMethodArgumentResolverComposite, is clearly the request processing.

  InvocableHandlerMethod subclass ServletInvocableHandlerMethod has important properties HandlerMethodReturnValueHandlerComposite, is clearly a response to be processed.

  This class ServletInvocableHandlerMethod HandlerAdapter process for each request, it will instantiate a (the above-mentioned properties are set by the HandlerAdapter), respectively, and return to process the request. (RequestMappingHandlerAdapter source, when instantiated ServletInvocableHandlerMethod important attributes are set mentioned above)

  

MethodParameter categories:

  HandlerMethod class attribute type parameters, is a MethodParameter array. MethodParameter method is a package of information parameters specific tools, index information including a position parameter, a type, annotations, parameter names and the like.

  HandlerMethod the instantiation, the constructor initializes this array, then only a part of the initialization data, processing the request in HandlerAdapter will improve other properties, then handed over to the appropriate HandlerMethodArgumentResolver interface processing.

  DeptController to class as an example:

@Controller
@RequestMapping(value = "/dept")
public classDeptController{

  @Autowired
  private IDeptService deptService;
  
  @RequestMapping("/update")
  @ResponseBody
  public String update(Dept dept) {
    deptService.saveOrUpdate(dept);
    return "success";
  }
  
}

  (Just initialize data)  

  (HandlerAdapter data after treatment)

RequestCondition Interface:

  Introduced after Spring3.1 version. Request condition is mapped in SpringMVC base, may be combine, compareTo, getMatchingCondition operation. This interface is mapped to match the key interfaces, which getMatchingCondition method of having been able to find a suitable map.

  

RequestMappingInfo categories:

  Introduced after Spring3.1 version. It is a package of various requests and implements the class mapping conditions RequestCondition interface.

  有各种RequestCondition实现类属性,patternsCondition,methodsCondition,paramsCondition,headersCondition,consumesCondition以及producesCondition,这个请求条件看属性名也了解,分别代表http请求的路径模式、方法、参数、头部等信息。

  

RequestMappingHandlerMapping类:

   处理请求与HandlerMethod映射关系的一个类。

2.Web服务器启动的时候,SpringMVC到底做了什么。

先看AbstractHandlerMethodMapping的initHandlerMethods方法中。

我们进入createRequestMappingInfo方法看下是如何构造RequestMappingInfo对象的。

PatternsRequestCondition构造函数:

类对应的RequestMappingInfo存在的话,跟方法对应的RequestMappingInfo进行combine操作。

然后使用符合条件的method来注册各种HandlerMethod。

下面我们来看下各种RequestCondition接口的实现类的combine操作。

PatternsRequestCondition:

RequestMethodsRequestCondition:

方法的请求条件,用个set直接add即可。

其他相关的RequestConditon实现类读者可自行查看源码。

最终,RequestMappingHandlerMapping中两个比较重要的属性

private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();

private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();

T为RequestMappingInfo。

构造完成。

 

我们知道,SpringMVC的分发器DispatcherServlet会根据浏览器的请求地址获得HandlerExecutionChain。

这个过程我们看是如何实现的。

首先看HandlerMethod的获得(直接看关键代码了):

这里的比较器是使用RequestMappingInfo的compareTo方法(RequestCondition接口定义的)。

然后构造HandlerExecutionChain加上拦截器

实例

写了这么多,来点例子让我们验证一下吧。

@Controller
@RequestMapping(value = "/wildcard")
public classTestWildcardController{
  
  @RequestMapping("/test/**")
  @ResponseBody
  public String test1(ModelAndView view) {
    view.setViewName("/test/test");
    view.addObject("attr", "TestWildcardController -> /test/**");
    return view;
  }
  
  @RequestMapping("/test/*")
  @ResponseBody
  public String test2(ModelAndView view) {
    view.setViewName("/test/test");
    view.addObject("attr", "TestWildcardController -> /test*");
    return view;
  }
  
  @RequestMapping("test?")
  @ResponseBody
  public String test3(ModelAndView view) {
    view.setViewName("/test/test");
    view.addObject("attr", "TestWildcardController -> test?");
    return view;
  }
  
  @RequestMapping("test/*")
  @ResponseBody
  public String test4(ModelAndView view) {
    view.setViewName("/test/test");
    view.addObject("attr", "TestWildcardController -> test/*");
    return view;
  }
  
}

由于这里的每个pattern都带了*因此,都不会加入到urlMap中,但是handlerMethods还是有的。

当我们访问:http://localhost:8888/SpringMVCDemo/wildcard/test1的时候。

会先根据 "/wildcard/test1" 找urlMap对应的RequestMappingInfo集合,找不到的话取handlerMethods集合中所有的key集合(也就是RequestMappingInfo集合)。

然后进行匹配,匹配根据RequestCondition的getMatchingCondition方法。

最终匹配到2个RequestMappingInfo:

然后会使用比较器进行排序。

之前也分析过,比较器是有优先级的。

我们看到,RequestMappingInfo除了pattern,其他属性都是一样的。

我们看下PatternsRequestCondition比较的逻辑:

因此,/test*的通配符比/test?的多,因此,最终选择了/test?

直接比较优先于通配符。

@Controller
@RequestMapping(value = "/priority")
public classTestPriorityController{
  
  @RequestMapping(method = RequestMethod.GET)
  @ResponseBody
  public String test1(ModelAndView view) {
    view.setViewName("/test/test");
    view.addObject("attr", "其他condition相同,带有method属性的优先级高");
    return view;
  }
  
  @RequestMapping()
  @ResponseBody
  public String test2(ModelAndView view) {
    view.setViewName("/test/test");
    view.addObject("attr", "其他condition相同,不带method属性的优先级高");
    return view;
  }
  
}

 这里例子,其他requestCondition都一样,只有RequestMethodCondition不一样。

看出,方法多的优先级越多。

 

至于其他的RequestCondition,大家自行查看源码吧。

资源文件映射

以上分析均是基于Controller方法的映射(RequestMappingHandlerMapping)。

SpringMVC中还有静态文件的映射,SimpleUrlHandlerMapping。

DispatcherServlet找对应的HandlerExecutionChain的时候会遍历属性handlerMappings,这个一个实现了HandlerMapping接口的集合。

由于我们在*-dispatcher.xml中加入了以下配置:

<mvc:resourceslocation="/static/"mapping="/static/**"/>

 Spring解析配置文件会使用ResourcesBeanDefinitionParser进行解析的时候,会实例化出SimpleUrlHandlerMapping。

其中注册的HandlerMethod为ResourceHttpRequestHandler。

访问地址:http://localhost:8888/SpringMVCDemo/static/js/jquery-1.11.0.js

地址匹配到/static/**。

最终SimpleUrlHandlerMapping找到对应的Handler -> ResourceHttpRequestHandler。

ResourceHttpRequestHandler进行handleRequest的时候,直接输出资源文件的文本内容。

总结

大致上整理了一下SpringMVC对请求的处理,包括其中比较关键的类和接口,希望对读者有帮助。

让自己对SpringMVC有了更深入的认识,也为之后分析数据绑定,拦截器、HandlerAdapter等打下基础。

参考资料

http://jinnianshilongnian.iteye.com/blog/1684403

http://my.oschina.net/HeliosFly/blog/212329


---------------------
作者:format丶
来源:CNBLOGS
原文:https://www.cnblogs.com/fangjian0423/p/springMVC-request-mapping.html
版权声明:本文为作者原创文章,转载请附上博文链接!

Guess you like

Origin www.cnblogs.com/webfactory/p/11462917.html