天天看点

SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

刚接触springmvc,对它的xml文件配置一直比较模模糊糊,最近花了一点时间稍微看了下源代码,再加上调试,开始逐渐理解它,网上的类似的内容有很多,写本文主要是自己加深一下理解。本文适合用过springmvc的开发者,言归正传,首先搭建一个最简单的工程体验一下。 

该工程是基于maven的,pom配置不再说明,所使用的spring版本4.0.5。 

首先是web.xml文件配置,最简单的配置 

<a href="http://my.oschina.net/pingpangkuangmo/blog/376293#">?</a>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<code>&lt;!doctype web-app public</code>

<code> </code><code>"-//sun microsystems, inc.//dtd web application 2.3//en"</code>

<code>&lt;web-app&gt;</code>

<code>  </code><code>&lt;display-name&gt;archetype created web application&lt;/display-name&gt;</code>

<code>  </code><code>&lt;servlet&gt;</code>

<code>        </code><code>&lt;servlet-name&gt;mvc&lt;/servlet-name&gt;</code>

<code>        </code><code>&lt;servlet-</code><code>class</code><code>&gt;org.springframework.web.servlet.dispatcherservlet&lt;/servlet-</code><code>class</code><code>&gt;</code>

<code>        </code><code>&lt;load-on-startup&gt;</code><code>1</code><code>&lt;/load-on-startup&gt;</code>

<code>    </code><code>&lt;/servlet&gt;</code>

<code>    </code><code>&lt;servlet-mapping&gt;</code>

<code>        </code><code>&lt;url-pattern&gt;/*&lt;/url-pattern&gt;</code>

<code>    </code><code>&lt;/servlet-mapping&gt;</code>

<code>&lt;/web-app&gt;</code>

然后是mvc-servlet.xml文件的配置,上面配置dispatcherservlet会默认加载[servlet-name]-servlet.xml文件。对于我的配置,会去加载mvc-servlet.xml文件。 

mvc-servlet.xml文件的内容: 

18

19

20

21

22

23

24

25

26

27

28

29

<code>&lt;?xml version=</code><code>"1.0"</code> <code>encoding=</code><code>"utf-8"</code> <code>?&gt;</code>

<code>    </code><code>xsi:schemalocation="http:</code><code>//www.springframework.org/schema/beans</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/beans/spring-beans-3.1.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/mvc</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/mvc/spring-mvc-3.1.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/util</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/util/spring-util-2.0.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/context</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/context/spring-context-3.2.xsd"&gt;</code>

<code>    </code><code>&lt;bean name=</code><code>"/index"</code> <code>class</code><code>=</code><code>"com.lg.mvc.homeaction"</code><code>&gt;&lt;/bean&gt;</code>

<code>    </code><code>&lt;bean</code><code>class</code><code>=</code><code>"org.springframework.web.servlet.view.freemarker.freemarkerconfigurer"</code><code>&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"templateloaderpath"</code> <code>value=</code><code>"/web-inf/views"</code> <code>/&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"defaultencoding"</code> <code>value=</code><code>"utf-8"</code> <code>/&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"freemarkersettings"</code><code>&gt;</code>

<code>            </code><code>&lt;props&gt;</code>

<code>                </code><code>&lt;prop key=</code><code>"locale"</code><code>&gt;zh_cn&lt;/prop&gt;</code>

<code>            </code><code>&lt;/props&gt;</code>

<code>        </code><code>&lt;/property&gt;</code>

<code>    </code><code>&lt;/bean&gt;</code>

<code>    </code><code>&lt;bean</code><code>class</code><code>=</code><code>"org.springframework.web.servlet.view.freemarker.freemarkerviewresolver"</code><code>&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"suffix"</code> <code>value=</code><code>".html"</code> <code>/&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"contenttype"</code> <code>value=</code><code>"text/html;charset=utf-8"</code> <code>/&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"requestcontextattribute"</code> <code>value=</code><code>"request"</code> <code>/&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"exposerequestattributes"</code> <code>value=</code><code>"true"</code> <code>/&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"exposesessionattributes"</code> <code>value=</code><code>"true"</code> <code>/&gt;</code>

<code>&lt;/beans&gt;</code>

在该配置中定义了一个homeaction的bean。内容为: 

<code>package</code> <code>com.lg.mvc;</code>

<code>import</code> <code>javax.servlet.http.httpservletrequest;</code>

<code>import</code> <code>javax.servlet.http.httpservletresponse;</code>

<code>import</code> <code>org.springframework.web.servlet.modelandview;</code>

<code>import</code> <code>org.springframework.web.servlet.mvc.controller;</code>

<code>public</code> <code>class</code> <code>homeaction</code><code>implements</code> <code>controller{</code>

<code>    </code><code>@override</code>

<code>    </code><code>public</code> <code>modelandview handlerequest(httpservletrequest request,</code>

<code>            </code><code>httpservletresponse response)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>return</code> <code>new</code> <code>modelandview(</code><code>"hello"</code><code>);</code>

<code>    </code><code>}</code>

<code>}</code>

这是最原始的mvc做法,要继承controller接口,先从原始的说起,最后再过渡到@controller和@requestmapping注解式的配置。它在mvc-serlet.xml文件中的配置有一个关键的属性name="/index"。 

web-inf/view目录下有一个简单的hello.html,内容为: 

<code>&lt;html&gt;</code>

<code>    </code><code>&lt;head&gt;</code>

<code>    </code> 

<code>    </code><code>&lt;/head&gt;</code>

<code>    </code><code>&lt;body&gt;</code>

<code>        </code><code>hello lg !</code>

<code>    </code><code>&lt;/body&gt;</code>

<code>&lt;/html&gt;</code>

至此该工程就写完了,部署到tomcat中,项目路径为/,运行一下。 

访问 http://localhost:8080/index 

SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

至此整个工程就算搭建成功了。 

下面就要说说原理了。 

用过python django框架的都知道django对于访问方式的配置就是,一个url路径和一个函数配对,你访问这个url,就会直接调用这个函数,简单明了。对于java的面向对象来说,就要分两步走。第一步首先要找到是哪个对象,即handler,本工程的handler则是homeaction对象。第二步要找到访问的函数,即homeaction的handlerequest方法。所以就出现了两个源码接口 handlermapping和handleradapter,前者负责第一步,后者负责第二步。借用网上的springmvc架构图。 

SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

handlermapping接口的实现(只举了我认识的几个) : 

beannameurlhandlermapping :通过对比url和bean的name找到对应的对象 

simpleurlhandlermapping :也是直接配置url和对应bean,比beannameurlhandlermapping功能更多 

defaultannotationhandlermapping : 主要是针对注解配置@requestmapping的,已过时 

requestmappinghandlermapping :取代了上面一个 

handleradapter 接口实现: 

httprequesthandleradapter : 要求handler实现httprequesthandler接口,该接口的方法为                                                             void handlerequest(httpservletrequest request, httpservletresponse response)也就是  handler必须有一个handlerequest方法 

simplecontrollerhandleradapter:要求handler实现controller接口,该接口的方法为modelandview handlerequest(httpservletrequest request, httpservletresponse response),也就是本工程采用的 

annotationmethodhandleradapter :和上面的defaultannotationhandlermapping配对使用的,也已过时 

requestmappinghandleradapter : 和上面的requestmappinghandlermapping配对使用,针对@requestmapping 

先简单的说下这个工程的流程,访问http://localhost:8080/index首先由dispatcherservlet进行转发,通过beannameurlhandlermapping(含有 /index-&gt;homeaction的配置),找到了homeaction,然后再拿homeaction和每个adapter进行适配,由于homeaction实现了controller接口,所以最终会有simplecontrollerhandleradapter来完成对homeaction的handlerequest方法的调度。然后就顺利的执行了我们想要的方法,后面的内容不在本节中说明。 

了解了大概流程,然后就需要看源代码了。 

首先就是springmvc的入口类,dispatcherservlet,它实现了servlet接口,不再详细说dispatcherservlet的细节,不然又是一大堆的内容。每次请求都会调用它的doservice-&gt;dodispatch,我们关注的重点就在dodispatch方法中。 

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

<code>protected</code> <code>void</code> <code>dodispatch(httpservletrequest request, httpservletresponse response)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>httpservletrequest processedrequest = request;</code>

<code>        </code><code>handlerexecutionchain mappedhandler =</code><code>null</code><code>;</code>

<code>        </code><code>boolean</code> <code>multipartrequestparsed =</code><code>false</code><code>;</code>

<code>        </code><code>webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request);</code>

<code>        </code><code>try</code> <code>{</code>

<code>            </code><code>modelandview mv =</code><code>null</code><code>;</code>

<code>            </code><code>exception dispatchexception =</code><code>null</code><code>;</code>

<code>            </code><code>try</code> <code>{</code>

<code>                </code><code>processedrequest = checkmultipart(request);</code>

<code>                </code><code>multipartrequestparsed = (processedrequest != request);</code>

<code>                      </code><code>//这个是重点,第一步由handlermapping找到对应的handler</code>

<code>                </code><code>// determine handler for the current request.</code>

<code>                </code><code>mappedhandler = gethandler(processedrequest);</code>

<code>                </code><code>if</code> <code>(mappedhandler ==</code><code>null</code> <code>|| mappedhandler.gethandler() ==</code><code>null</code><code>) {</code>

<code>                    </code><code>nohandlerfound(processedrequest, response);</code>

<code>                    </code><code>return</code><code>;</code>

<code>                </code><code>}</code>

<code>                </code><code>// determine handler adapter for the current request.</code>

<code>                       </code><code>//这是第二步,找到合适的handleradapter,然后由它来调度执行handler的方法</code>

<code>                </code><code>handleradapter ha = gethandleradapter(mappedhandler.gethandler());</code>

<code>                </code><code>// process last-modified header, if supported by the handler.</code>

<code>                </code><code>string method = request.getmethod();</code>

<code>                </code><code>boolean</code> <code>isget =</code><code>"get"</code><code>.equals(method);</code>

<code>                </code><code>if</code> <code>(isget ||</code><code>"head"</code><code>.equals(method)) {</code>

<code>                    </code><code>long</code> <code>lastmodified = ha.getlastmodified(request, mappedhandler.gethandler());</code>

<code>                    </code><code>if</code> <code>(logger.isdebugenabled()) {</code>

<code>                        </code><code>logger.debug(</code><code>"last-modified value for ["</code> <code>+ getrequesturi(request) +</code><code>"] is: "</code> <code>+ lastmodified);</code>

<code>                    </code><code>}</code>

<code>                    </code><code>if</code> <code>(</code><code>new</code> <code>servletwebrequest(request, response).checknotmodified(lastmodified) &amp;&amp; isget) {</code>

<code>                        </code><code>return</code><code>;</code>

<code>                </code><code>if</code> <code>(!mappedhandler.applyprehandle(processedrequest, response)) {</code>

<code>                </code><code>try</code> <code>{</code>

<code>                    </code><code>// actually invoke the handler.</code>

<code>                    </code><code>mv = ha.handle(processedrequest, response, mappedhandler.gethandler());</code>

<code>                </code><code>finally</code> <code>{</code>

<code>                    </code><code>if</code> <code>(asyncmanager.isconcurrenthandlingstarted()) {</code>

<code>                </code><code>applydefaultviewname(request, mv);</code>

<code>                </code><code>mappedhandler.applyposthandle(processedrequest, response, mv);</code>

<code>            </code><code>}</code>

<code>            </code><code>catch</code> <code>(exception ex) {</code>

<code>                </code><code>dispatchexception = ex;</code>

<code>            </code><code>processdispatchresult(processedrequest, response, mappedhandler, mv, dispatchexception);</code>

<code>        </code><code>}</code>

<code>        </code><code>catch</code> <code>(exception ex) {</code>

<code>            </code><code>triggeraftercompletion(processedrequest, response, mappedhandler, ex);</code>

<code>        </code><code>catch</code> <code>(error err) {</code>

<code>            </code><code>triggeraftercompletionwitherror(processedrequest, response, mappedhandler, err);</code>

<code>        </code><code>finally</code> <code>{</code>

<code>            </code><code>if</code> <code>(asyncmanager.isconcurrenthandlingstarted()) {</code>

<code>                </code><code>// instead of posthandle and aftercompletion</code>

<code>                </code><code>mappedhandler.applyafterconcurrenthandlingstarted(processedrequest, response);</code>

<code>                </code><code>return</code><code>;</code>

<code>            </code><code>// clean up any resources used by a multipart request.</code>

<code>            </code><code>if</code> <code>(multipartrequestparsed) {</code>

<code>                </code><code>cleanupmultipart(processedrequest);</code>

第一步详细查看: 

<code>protected</code> <code>handlerexecutionchain gethandler(httpservletrequest request)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>for</code> <code>(handlermapping hm :</code><code>this</code><code>.handlermappings) {</code>

<code>            </code><code>if</code> <code>(logger.istraceenabled()) {</code>

<code>                </code><code>logger.trace(</code>

<code>                        </code><code>"testing handler map ["</code> <code>+ hm +</code><code>"] in dispatcherservlet with name '"</code> <code>+ getservletname() +</code><code>"'"</code><code>);</code>

<code>            </code><code>handlerexecutionchain handler = hm.gethandler(request);</code>

<code>            </code><code>if</code> <code>(handler !=</code><code>null</code><code>) {</code>

<code>                </code><code>return</code> <code>handler;</code>

<code>        </code><code>return</code> <code>null</code><code>;</code>

可以看到就是通过遍历所有已注册的handlermapping来找到对应的handler,然后构建出一个handlerexecutionchain,它包含了handler和handlermapping本身的一些拦截器,如下 

<code>public</code> <code>class</code> <code>handlerexecutionchain {</code>

<code>    </code><code>private</code> <code>final</code> <code>object handler;</code>

<code>    </code><code>private</code> <code>handlerinterceptor[] interceptors;</code>

<code>    </code><code>private</code> <code>list&lt;handlerinterceptor&gt; interceptorlist;</code>

<code>        </code> 

<code>        </code><code>//其他代码省略</code>

其中handlermapping的gethandler实现: 

<code>public</code> <code>final</code> <code>handlerexecutionchain gethandler(httpservletrequest request)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>object handler = gethandlerinternal(request);</code>

<code>        </code><code>if</code> <code>(handler ==</code><code>null</code><code>) {</code>

<code>            </code><code>handler = getdefaulthandler();</code>

<code>            </code><code>return</code> <code>null</code><code>;</code>

<code>        </code><code>// bean name or resolved handler?</code>

<code>        </code><code>if</code> <code>(handler</code><code>instanceof</code> <code>string) {</code>

<code>            </code><code>string handlername = (string) handler;</code>

<code>            </code><code>handler = getapplicationcontext().getbean(handlername);</code>

<code>        </code><code>return</code> <code>gethandlerexecutionchain(handler, request);</code>

这里的gethandlerinternal(request)是个抽象方法,由具体的handlermapping来实现,获取到的handler如果为空,则获取默认配置的handler,如果handler为string类型,则表示这个则会去spring容器里面去找这样名字的bean。 

再看下beannameurlhandlermapping的gethandlerinternal(request)的具体实现(通过一系列的接口设计,之后再好好看看这个设计,到beannameurlhandlermapping这只用实现该方法中的一部分),如下 

<code>public</code> <code>class</code> <code>beannameurlhandlermapping</code><code>extends</code> <code>abstractdetectingurlhandlermapping {</code>

<code>    </code><code>/**</code>

<code>     </code><code>* checks name and aliases of the given bean for urls, starting with "/".</code>

<code>     </code><code>*/</code>

<code>    </code><code>protected</code> <code>string[] determineurlsforhandler(string beanname) {</code>

<code>        </code><code>list&lt;string&gt; urls =</code><code>new</code> <code>arraylist&lt;string&gt;();</code>

<code>        </code><code>if</code> <code>(beanname.startswith(</code><code>"/"</code><code>)) {</code>

<code>            </code><code>urls.add(beanname);</code>

<code>        </code><code>string[] aliases = getapplicationcontext().getaliases(beanname);</code>

<code>        </code><code>for</code> <code>(string alias : aliases) {</code>

<code>            </code><code>if</code> <code>(alias.startswith(</code><code>"/"</code><code>)) {</code>

<code>                </code><code>urls.add(alias);</code>

<code>        </code><code>return</code> <code>stringutils.tostringarray(urls);</code>

这里面注释说,bean的name必须以/开头,它才处理,将信息存储在map&lt;string, object&gt; handlermap中,对于本工程来说就是{'/index':homeaction对象}。 

至此这里完成了第一步,下面开始第二步,即方法handleradapter ha = gethandleradapter(mappedhandler.gethandler());的具体实现: 

<code>protected</code> <code>handleradapter gethandleradapter(object handler)</code><code>throws</code> <code>servletexception {</code>

<code>        </code><code>for</code> <code>(handleradapter ha :</code><code>this</code><code>.handleradapters) {</code>

<code>                </code><code>logger.trace(</code><code>"testing handler adapter ["</code> <code>+ ha +</code><code>"]"</code><code>);</code>

<code>            </code><code>if</code> <code>(ha.supports(handler)) {</code>

<code>                </code><code>return</code> <code>ha;</code>

<code>        </code><code>throw</code> <code>new</code> <code>servletexception(</code><code>"no adapter for handler ["</code> <code>+ handler +</code>

<code>                </code><code>"]: the dispatcherservlet configuration needs to include a handleradapter that supports this handler"</code><code>);</code>

遍历所有的handleradapter,判断他们是否支持这个handler。 

我们来看下httprequesthandleradapter的supports(handler)方法: 

<code>public</code> <code>class</code> <code>httprequesthandleradapter</code><code>implements</code> <code>handleradapter {</code>

<code>    </code><code>public</code> <code>boolean</code> <code>supports(object handler) {</code>

<code>          </code><code>//就是判断handler是否实现了httprequesthandler接口</code>

<code>        </code><code>return</code> <code>(handler</code><code>instanceof</code> <code>httprequesthandler);</code>

<code>    </code><code>public</code> <code>modelandview handle(httpservletrequest request, httpservletresponse response, object handler)</code>

<code>            </code><code>throws</code> <code>exception {</code>

<code>           </code><code>//若handler实现了httprequesthandler接口,则调用该接口的方法,执行我们在该方法中写的业务逻辑</code>

<code>        </code><code>((httprequesthandler) handler).handlerequest(request, response);</code>

<code>    </code><code>public</code> <code>long</code> <code>getlastmodified(httpservletrequest request, object handler) {</code>

<code>        </code><code>if</code> <code>(handler</code><code>instanceof</code> <code>lastmodified) {</code>

<code>            </code><code>return</code> <code>((lastmodified) handler).getlastmodified(request);</code>

<code>        </code><code>return</code> <code>-1l;</code>

同理simplecontrollerhandleradapter也是这样类似的逻辑 

<code>public</code> <code>class</code> <code>simplecontrollerhandleradapter</code><code>implements</code> <code>handleradapter {</code>

<code>        </code><code>return</code> <code>(handler</code><code>instanceof</code> <code>controller);</code>

<code>        </code><code>return</code> <code>((controller) handler).handlerequest(request, response);</code>

剩余两个annotationmethodhandleradapter和requestmappinghandleradapter就比较复杂,我也没看。 

按照本工程的配置,则simplecontrollerhandleradapter是支持homeaction的,然后就会执行simplecontrollerhandleradapter的handle(processedrequest, response, mappedhandler.gethandler())方法。本质上就会调用homeaction实现controller接口的方法。至此就分析完了。 

了解过程了之后,然后就是最重要的也是经常配置出问题的地方。dispatcherservlet的handlermappings和handleradapters的来源问题。 

dispatcherservlet初始化的时候,会调用一个方法如下: 

<code>protected</code> <code>void</code> <code>initstrategies(applicationcontext context) {</code>

<code>        </code><code>initmultipartresolver(context);</code>

<code>        </code><code>initlocaleresolver(context);</code>

<code>        </code><code>initthemeresolver(context);</code>

<code>//初始化一些handlermapping</code>

<code>        </code><code>inithandlermappings(context);</code>

<code>//初始化一些handleradapter</code>

<code>        </code><code>inithandleradapters(context);</code>

<code>        </code><code>inithandlerexceptionresolvers(context);</code>

<code>        </code><code>initrequesttoviewnametranslator(context);</code>

<code>        </code><code>initviewresolvers(context);</code>

<code>        </code><code>initflashmapmanager(context);</code>

这里可以看到,它会初始化一些handlermapping和handleradapter,这两个方法非常重要,理解了这两个方法你就会知道,配置不对问题出在哪里,下面具体看下这两个方法: 

<code>private</code> <code>void</code> <code>inithandlermappings(applicationcontext context) {</code>

<code>        </code><code>this</code><code>.handlermappings =</code><code>null</code><code>;</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.detectallhandlermappings) {</code>

<code>            </code><code>// find all handlermappings in the applicationcontext, including ancestor contexts.</code>

<code>            </code><code>map&lt;string, handlermapping&gt; matchingbeans =</code>

<code>                    </code><code>beanfactoryutils.beansoftypeincludingancestors(context, handlermapping.</code><code>class</code><code>,</code><code>true</code><code>,</code><code>false</code><code>);</code>

<code>            </code><code>if</code> <code>(!matchingbeans.isempty()) {</code>

<code>                </code><code>this</code><code>.handlermappings =</code><code>new</code> <code>arraylist&lt;handlermapping&gt;(matchingbeans.values());</code>

<code>                </code><code>// we keep handlermappings in sorted order.</code>

<code>                </code><code>ordercomparator.sort(</code><code>this</code><code>.handlermappings);</code>

<code>        </code><code>else</code> <code>{</code>

<code>                </code><code>handlermapping hm = context.getbean(handler_mapping_bean_name, handlermapping.</code><code>class</code><code>);</code>

<code>                </code><code>this</code><code>.handlermappings = collections.singletonlist(hm);</code>

<code>            </code><code>catch</code> <code>(nosuchbeandefinitionexception ex) {</code>

<code>                </code><code>// ignore, we'll add a default handlermapping later.</code>

<code>        </code><code>// ensure we have at least one handlermapping, by registering</code>

<code>        </code><code>// a default handlermapping if no other mappings are found.</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.handlermappings ==</code><code>null</code><code>) {</code>

<code>            </code><code>this</code><code>.handlermappings = getdefaultstrategies(context, handlermapping.</code><code>class</code><code>);</code>

<code>            </code><code>if</code> <code>(logger.isdebugenabled()) {</code>

<code>                </code><code>logger.debug(</code><code>"no handlermappings found in servlet '"</code> <code>+ getservletname() +</code><code>"': using default"</code><code>);</code>

detectallhandlermappings是dispatcherservlet的一个属性,你是可以在web.xml中配置的,默认是true,如果为true,则会去从本工程mvc-servlet.xml文件中去探测所有实现了handlermapping的bean,如果有,则加入dispatcherservlet的handlermappings中。如果detectallhandlermappings为false,则直接去容器中找id="handlermapping"且实现了handlermapping的bean.如果以上都没找到,则会去加载默认的handlermapping。 

<code>/** detect all handlermappings or just expect "handlermapping" bean? */</code>

<code>    </code><code>private</code> <code>boolean</code> <code>detectallhandlermappings =</code><code>true</code><code>;</code>

本工程由于没有配置handlermapping,所以它会去加载默认的,下面看看默认的配置是什么 

<code>protected</code> <code>&lt;t&gt; list&lt;t&gt; getdefaultstrategies(applicationcontext context, class&lt;t&gt; strategyinterface) {</code>

<code>        </code><code>string key = strategyinterface.getname();</code>

<code>//defaultstrategies存储了默认的配置</code>

<code>        </code><code>string value = defaultstrategies.getproperty(key);</code>

<code>        </code><code>if</code> <code>(value !=</code><code>null</code><code>) {</code>

<code>            </code><code>string[] classnames = stringutils.commadelimitedlisttostringarray(value);</code>

<code>            </code><code>list&lt;t&gt; strategies =</code><code>new</code> <code>arraylist&lt;t&gt;(classnames.length);</code>

<code>            </code><code>for</code> <code>(string classname : classnames) {</code>

<code>                    </code><code>class&lt;?&gt; clazz = classutils.forname(classname, dispatcherservlet.</code><code>class</code><code>.getclassloader());</code>

<code>                    </code><code>object strategy = createdefaultstrategy(context, clazz);</code>

<code>                    </code><code>strategies.add((t) strategy);</code>

<code>                </code><code>catch</code> <code>(classnotfoundexception ex) {</code>

<code>                    </code><code>throw</code> <code>new</code> <code>beaninitializationexception(</code>

<code>                            </code><code>"could not find dispatcherservlet's default strategy class ["</code> <code>+ classname +</code>

<code>                                    </code><code>"] for interface ["</code> <code>+ key +</code><code>"]"</code><code>, ex);</code>

<code>                </code><code>catch</code> <code>(linkageerror err) {</code>

<code>                            </code><code>"error loading dispatcherservlet's default strategy class ["</code> <code>+ classname +</code>

<code>                                    </code><code>"] for interface ["</code> <code>+ key +</code><code>"]: problem with class file or dependent class"</code><code>, err);</code>

<code>            </code><code>return</code> <code>strategies;</code>

<code>            </code><code>return</code> <code>new</code> <code>linkedlist&lt;t&gt;();</code>

继续看看defaultstrategies是如何初始化的: 

<code>private</code> <code>static</code> <code>final</code> <code>properties defaultstrategies;</code>

<code>    </code><code>static</code> <code>{</code>

<code>        </code><code>// load default strategy implementations from properties file.</code>

<code>        </code><code>// this is currently strictly internal and not meant to be customized</code>

<code>        </code><code>// by application developers.</code>

<code>//这里的default_strategies_path就是dispatcherservlet.properties</code>

<code>            </code><code>classpathresource resource =</code><code>new</code> <code>classpathresource(default_strategies_path, dispatcherservlet.</code><code>class</code><code>);</code>

<code>            </code><code>defaultstrategies = propertiesloaderutils.loadproperties(resource);</code>

<code>        </code><code>catch</code> <code>(ioexception ex) {</code>

<code>            </code><code>throw</code> <code>new</code> <code>illegalstateexception(</code><code>"could not load 'dispatcherservlet.properties': "</code> <code>+ ex.getmessage());</code>

这里使用静态代码块来加载配置文件dispatcherservlet.properties,它所在位置就是和dispatcherservlet同一目录下面的,如下图所示: 

SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

该默认的配置文件的内容如下: 

<code># default implementation classes</code><code>for</code> <code>dispatcherservlet's strategy interfaces.</code>

<code># used as fallback when no matching beans are found in the dispatcherservlet context.</code>

<code># not meant to be customized by application developers.</code>

<code>org.springframework.web.servlet.localeresolver=org.springframework.web.servlet.i18n.acceptheaderlocaleresolver</code>

<code>org.springframework.web.servlet.themeresolver=org.springframework.web.servlet.theme.fixedthemeresolver</code>

<code>#这里就是默认的handlermapping的配置</code>

<code>org.springframework.web.servlet.handlermapping=org.springframework.web.servlet.handler.beannameurlhandlermapping,\</code>

<code>    </code><code>org.springframework.web.servlet.mvc.annotation.defaultannotationhandlermapping</code>

<code>#这里就是默认的handleradapter的配置</code>

<code>org.springframework.web.servlet.handleradapter=org.springframework.web.servlet.mvc.httprequesthandleradapter,\</code>

<code>    </code><code>org.springframework.web.servlet.mvc.simplecontrollerhandleradapter,\</code>

<code>    </code><code>org.springframework.web.servlet.mvc.annotation.annotationmethodhandleradapter</code>

<code>org.springframework.web.servlet.handlerexceptionresolver=org.springframework.web.servlet.mvc.annotation.annotationmethodhandlerexceptionresolver,\</code>

<code>    </code><code>org.springframework.web.servlet.mvc.annotation.responsestatusexceptionresolver,\</code>

<code>    </code><code>org.springframework.web.servlet.mvc.support.defaulthandlerexceptionresolver</code>

<code>org.springframework.web.servlet.requesttoviewnametranslator=org.springframework.web.servlet.view.defaultrequesttoviewnametranslator</code>

<code>org.springframework.web.servlet.viewresolver=org.springframework.web.servlet.view.internalresourceviewresolver</code>

<code>org.springframework.web.servlet.flashmapmanager=org.springframework.web.servlet.support.sessionflashmapmanager</code>

也就是说,当你什么都没有配置时,默认会加载以上的配置。正是由于有了上述默认配置的beannameurlhandlermapping(它要求name必须是以/开头的),它才会存储我们在mvc-servlet.xml中配置的&lt;bean name="/index" class="com.lg.mvc.homeaction"&gt;&lt;/bean&gt;,同样正是由于有了simplecontrollerhandleradapter(由于handler实现了controller接口,所以它的support方法支持我们的handler),才会调度执行homeaction的handlerequest方法。