HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求来进行处理。当handlerMapping获取到执行请求的controller时,DispatcherServlte会根据controller对应的controller类型来调用相应的HandlerAdapter来进行处理。

        在贴源码之前先说一下HandlerAdapter处理的大体流程,这样就有一个大体的掌握。大体流程有三步:

        1.DispatcherServlte会根据配置文件信息注册HandlerAdapter,如果在配置文件中没有配置,那么DispatcherServlte会获取HandlerAdapter的默认配置,如果是读取默认配置的话,DispatcherServlte会读取DispatcherServlte.properties文件,该文件中配置了三种HandlerAdapter:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter。DispatcherServlte会将这三个HandlerAdapter对象存储到它的handlerAdapters这个集合属性中,这样就完成了HandlerAdapter的注册。

        2.DispatcherServlte会根据handlerMapping传过来的controller与已经注册好了的HandlerAdapter一一匹配,看哪一种HandlerAdapter是支持该controller类型的,如果找到了其中一种HandlerAdapter是支持传过来的controller类型,那么该HandlerAdapter会调用自己的handle方法,handle方法运用Java的反射机制执行controller的具体方法来获得ModelAndView,例如SimpleControllerHandlerAdapter是支持实现了controller接口的控制器,如果自己写的控制器实现了controller接口,那么SimpleControllerHandlerAdapter就会去执行自己写控制器中的具体方法来完成请求。

        下面是我自己写的代码。

        1.自己写的controller,就是我们自己写的控制器

          


[java]  view plain  copy


 
    
 
1. package com.wangbiao.springMVC;  
2.   
3. import javax.servlet.ServletContext;  
4. import javax.servlet.http.HttpServletRequest;  
5. import javax.servlet.http.HttpServletResponse;  
6.   
7. import org.springframework.web.servlet.ModelAndView;  
8. import org.springframework.web.servlet.mvc.multiaction.MultiActionController;  
9.   
10. public class HelloWorld extends  MultiActionController{  
11.   
12. public ModelAndView sayHelloWorld(HttpServletRequest request, HttpServletResponse response) {  
13. "param");  
14. "springMVC测试:helloWorld;"+param);  
15. new ModelAndView();  
16. "content", "springMVC HelloWorld:"+param);  
17. "springMVC/helloWorld");  
18. this.getServletContext();    
19. return mv;  
20.     }  
21.   
22. }


 2.SpringMVC配置文件

       


[java]  view plain  copy


 
    
 
1. <?xml version="1.0" encoding="UTF-8"?>  
2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       
3. "http://www.springframework.org/schema/beans"      
4. "http://www.springframework.org/schema/mvc"      
5. "http://www.springframework.org/schema/context"      
6. "http://www.springframework.org/schema/aop"      
7. "http://www.springframework.org/schema/tx"      
8. //www.springframework.org/schema/beans     
9. //www.springframework.org/schema/beans/spring-beans-3.0.xsd    
10. //www.springframework.org/schema/mvc    
11. //www.springframework.org/schema/mvc/spring-mvc-3.0.xsd    
12. //www.springframework.org/schema/context    
13. //www.springframework.org/schema/context/spring-context-3.0.xsd     
14. //www.springframework.org/schema/aop      
15. //www.springframework.org/schema/aop/spring-aop-3.0.xsd     
16. //www.springframework.org/schema/tx     
17. //www.springframework.org/schema/tx/spring-tx-3.0.xsd">   
18.         <!-- handlerMapping  -->  
19. "beanNameUrlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>   
20. "urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">  
21. "mappings">  
22.                               <props>  
23. "/springMVC.d">/HelloWorld</prop>  
24.                               </props>  
25.                  </property>  
26.     </bean>  
27.           
28. "/HelloWorld" class="com.wangbiao.springMVC.HelloWorld">  
29. "methodNameResolver">  
30. "methodNameResolver"/>  
31.                  </property>  
32.     </bean>  
33.     <!-- 在url中对应具体的方法,通过m后面带的参数来确定方法 -->  
34. "methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">      
35. "paramName"><value>m</value></property>     
36. "defaultMethodName"><value>execute</value></property>  
37.     </bean>  
38.       
39.       <!--视图解析器-->    
40. class="org.springframework.web.servlet.view.InternalResourceViewResolver">    
41.             <!-- webroot到一指定文件夹文件路径 -->    
42. "prefix" value="/"/>    
43.             <!-- 视图名称后缀  -->    
44. "suffix" value=".jsp"/>    
45.             </bean>              
46.     </beans>


下面是源码

1.DispatcherServlet注册HandlerAdapter。DispatcherServlet的initHandlerAdapters方法,红色标记的部分是关键。由于在配置文件中没有对HandlerAdapter的相关配置,所以DispatcherServlet获取到的HandlerAdapter是三个默认的HandlerAdapter对象,分别是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,并将这三个对象存入handlerAdapter属性中去。


[java]  view plain  copy


 
    
 
1. private void initHandlerAdapters(ApplicationContext context) {  
2. this.handlerAdapters = null;  
3.   
4. if (this.detectAllHandlerAdapters) {  
5. // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.  
6.             Map<String, HandlerAdapter> matchingBeans =  
7. class, true, false);  
8. if (!matchingBeans.isEmpty()) {  
9. this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());  
10. // We keep HandlerAdapters in sorted order.  
11. this.handlerAdapters);  
12.             }  
13.         }  
14. else {  
15. try {  
16. class);  
17. this.handlerAdapters = Collections.singletonList(ha);  
18.             }  
19. catch (NoSuchBeanDefinitionException ex) {  
20. // Ignore, we'll add a default HandlerAdapter later.  
21.             }  
22.         }  
23.   
24. // Ensure we have at least some HandlerAdapters, by registering  
25. // default HandlerAdapters if no other adapters are found.  
26. if (this.handlerAdapters == null) {  
27. this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);  
28. if (logger.isDebugEnabled()) {  
29. "No HandlerAdapters found in servlet '" + getServletName() + "': using default");  
30.             }  
31.         }  
32.     }



2.根据handlerMapping传过来的Handler对象与DispatcherServlet集合属性handlerAdapter中的HandlerAdapter一一匹配,如果有支持Handler对象的HandlerAdapter,那么HandlerAdapter就会调用自己的handle方法处理请求。


[java]  view plain  copy


 
    
 
1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
2.         HttpServletRequest processedRequest = request;  
3. null;  
4. int interceptorIndex = -1;  
5.   
6. try {  
7.             ModelAndView mv;  
8. boolean errorView = false;  
9.   
10. try {  
11.                 processedRequest = checkMultipart(request);  
12.   
13. // Determine handler for the current request.  
14. false);  
15. if (mappedHandler == null || mappedHandler.getHandler() == null) {  
16.                     noHandlerFound(processedRequest, response);  
17. return;  
18.                 }  
19.   
20. // Determine handler adapter for the current request.  
21.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
22.   
23. // Process last-modified header, if supported by the handler.  
24.                 String method = request.getMethod();  
25. boolean isGet = "GET".equals(method);  
26. if (isGet || "HEAD".equals(method)) {  
27. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
28. if (logger.isDebugEnabled()) {  
29.                         String requestUri = urlPathHelper.getRequestUri(request);  
30. "Last-Modified value for [" + requestUri + "] is: " + lastModified);  
31.                     }  
32. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
33. return;  
34.                     }  
35.                 }  
36.   
37. // Apply preHandle methods of registered interceptors.  
38.                 HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();  
39. if (interceptors != null) {  
40. for (int i = 0; i < interceptors.length; i++) {  
41.                         HandlerInterceptor interceptor = interceptors[i];  
42. if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {  
43. null);  
44. return;  
45.                         }  
46.                         interceptorIndex = i;  
47.                     }  
48.                 }  
49.   
50. // Actually invoke the handler.  
51.                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
52.   
53. // Do we need view name translation?  
54. if (mv != null && !mv.hasView()) {  
55.                     mv.setViewName(getDefaultViewName(request));  
56.                 }  
57.   
58. // Apply postHandle methods of registered interceptors.  
59. if (interceptors != null) {  
60. for (int i = interceptors.length - 1; i >= 0; i--) {  
61.                         HandlerInterceptor interceptor = interceptors[i];  
62.                         interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);  
63.                     }  
64.                 }  
65.             }  
66. catch (ModelAndViewDefiningException ex) {  
67. "ModelAndViewDefiningException encountered", ex);  
68.                 mv = ex.getModelAndView();  
69.             }  
70. catch (Exception ex) {  
71. null ? mappedHandler.getHandler() : null);  
72.                 mv = processHandlerException(processedRequest, response, handler, ex);  
73. null);  
74.             }  
75.   
76. // Did the handler return a view to render?  
77. if (mv != null && !mv.wasCleared()) {  
78.                 render(mv, processedRequest, response);  
79. if (errorView) {  
80.                     WebUtils.clearErrorRequestAttributes(request);  
81.                 }  
82.             }  
83. else {  
84. if (logger.isDebugEnabled()) {  
85. "Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +  
86. "': assuming HandlerAdapter completed request handling");  
87.                 }  
88.             }  
89.   
90. // Trigger after-completion for successful outcome.  
91. null);  
92.         }  
93.   
94. catch (Exception ex) {  
95. // Trigger after-completion for thrown exception.  
96.             triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
97. throw ex;  
98.         }  
99. catch (Error err) {  
100. new NestedServletException("Handler processing failed", err);  
101. // Trigger after-completion for thrown exception.  
102.             triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
103. throw ex;  
104.         }  
105.   
106. finally {  
107. // Clean up any resources used by a multipart request.  
108. if (processedRequest != request) {  
109.                 cleanupMultipart(processedRequest);  
110.             }  
111.         }  
112.     }



getHandlerAdapter方法



[java]  view plain  copy


 

 
 
1. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  
2. for (HandlerAdapter ha : this.handlerAdapters) {  
3. if (logger.isTraceEnabled()) {  
4. "Testing handler adapter [" + ha + "]");  
5.             }  
6. if (ha.supports(handler)) {  
7. return ha;  
8.             }  
9.         }  
10. throw new ServletException("No adapter for handler [" + handler +  
11. "]: Does your handler implement a supported interface like Controller?");  
12.     }


HandlerAdapter接口



[java]  view plain  copy


 

1. /*
2.  * Copyright 2002-2008 the original author or authors.
3.  *
4.  * Licensed under the Apache License, Version 2.0 (the "License");
5.  * you may not use this file except in compliance with the License.
6.  * You may obtain a copy of the License at
7.  *
8.  *      http://www.apache.org/licenses/LICENSE-2.0
9.  *
10.  * Unless required by applicable law or agreed to in writing, software
11.  * distributed under the License is distributed on an "AS IS" BASIS,
12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13.  * See the License for the specific language governing permissions and
14.  * limitations under the License.
15.  */  
16.   
17. package org.springframework.web.servlet;  
18.   
19. import javax.servlet.http.HttpServletRequest;  
20. import javax.servlet.http.HttpServletResponse;  
21.   
22. /**
23.  * MVC framework SPI interface, allowing parameterization of core MVC workflow.
24.  *
25.  * <p>Interface that must be implemented for each handler type to handle a request.
26.  * This interface is used to allow the {@link DispatcherServlet} to be indefinitely
27.  * extensible. The DispatcherServlet accesses all installed handlers through this
28.  * interface, meaning that it does not contain code specific to any handler type.
29.  *
30.  * <p>Note that a handler can be of type <code>Object</code>. This is to enable
31.  * handlers from other frameworks to be integrated with this framework without
32.  * custom coding, as well as to allow for annotation handler objects that do
33.  * not obey any specific Java interface.
34.  *
35.  * <p>This interface is not intended for application developers. It is available
36.  * to handlers who want to develop their own web workflow.
37.  *
38.  * <p>Note: HandlerAdaptger implementators may implement the
39.  * {@link org.springframework.core.Ordered} interface to be able to specify a
40.  * sorting order (and thus a priority) for getting applied by DispatcherServlet.
41.  * Non-Ordered instances get treated as lowest priority.
42.  *
43.  * @author Rod Johnson
44.  * @author Juergen Hoeller
45.  * @see org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
46.  * @see org.springframework.web.servlet.handler.SimpleServletHandlerAdapter
47.  */  
48. public interface HandlerAdapter {  
49.       
50. /**
51.      * Given a handler instance, return whether or not this HandlerAdapter can
52.      * support it. Typical HandlerAdapters will base the decision on the handler
53.      * type. HandlerAdapters will usually only support one handler type each.
54.      * <p>A typical implementation:
55.      * <p><code>
56.      * return (handler instanceof MyHandler);
57.      * </code>
58.      * @param handler handler object to check
59.      * @return whether or not this object can use the given handler
60.      */  
61. boolean supports(Object handler);   
62.       
63. /**
64.      * Use the given handler to handle this request.
65.      * The workflow that is required may vary widely.
66.      * @param request current HTTP request
67.      * @param response current HTTP response
68.      * @param handler handler to use. This object must have previously been passed
69.      * to the <code>supports</code> method of this interface, which must have
70.      * returned <code>true</code>.
71.      * @throws Exception in case of errors
72.      * @return ModelAndView object with the name of the view and the required
73.      * model data, or <code>null</code> if the request has been handled directly
74.      */  
75. throws Exception;  
76.   
77. /**
78.      * Same contract as for HttpServlet's <code>getLastModified</code> method.
79.      * Can simply return -1 if there's no support in the handler class.
80.      * @param request current HTTP request
81.      * @param handler handler to use
82.      * @return the lastModified value for the given handler
83.      * @see javax.servlet.http.HttpServlet#getLastModified
84.      * @see org.springframework.web.servlet.mvc.LastModified#getLastModified
85.      */  
86. long getLastModified(HttpServletRequest request, Object handler);  
87.   
88. }


再来看一下自己写的控制器HelloWorld继承了MultiActionController。MultiActionController又继承了AbstractController,AbstractController实现了Controller。这样就看DispatcherServlet属性中的HandlerApater谁支持Controller类型的处理器了。在运行的过程中发现SimpleControllerHandlerAdapter是支持Controller类型的控制器的。


来看一下SimpleControllerHandlerAdapter的代码


[java]  view plain  copy

 
    
 
1. public class SimpleControllerHandlerAdapter implements HandlerAdapter {  
2.   
3. public boolean supports(Object handler) {  
4. return (handler instanceof Controller);  
5.     }  
6.   
7. public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
8. throws Exception {  
9.   
10. return ((Controller) handler).handleRequest(request, response);  
11.     }  
12.   
13. public long getLastModified(HttpServletRequest request, Object handler) {  
14. if (handler instanceof LastModified) {  
15. return ((LastModified) handler).getLastModified(request);  
16.         }  
17. return -1L;  
18.     }  
19.   
20. }


再看一下Controller源码,Controller接口只有一个handleRequest方法


[java]  view plain  copy


 

再看看实现了Controller接口的AbstractController类

1. public interface Controller {  
2.   
3. /**
4.      * Process the request and return a ModelAndView object which the DispatcherServlet
5.      * will render. A <code>null</code> return value is not an error: It indicates that
6.      * this object completed request processing itself, thus there is no ModelAndView
7.      * to render.
8.      * @param request current HTTP request
9.      * @param response current HTTP response
10.      * @return a ModelAndView to render, or <code>null</code> if handled directly
11.      * @throws Exception in case of errors
12.      */  
13. throws Exception;  
14.   
15. }


[java]  view plain  copy


 

 
 
1. public abstract class AbstractController extends WebContentGenerator implements Controller {  
2.   
3. private boolean synchronizeOnSession = false;  
4.   
5.   
6. /**
7.      * Set if controller execution should be synchronized on the session,
8.      * to serialize parallel invocations from the same client.
9.      * <p>More specifically, the execution of the <code>handleRequestInternal</code>
10.      * method will get synchronized if this flag is "true". The best available
11.      * session mutex will be used for the synchronization; ideally, this will
12.      * be a mutex exposed by HttpSessionMutexListener.
13.      * <p>The session mutex is guaranteed to be the same object during
14.      * the entire lifetime of the session, available under the key defined
15.      * by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a
16.      * safe reference to synchronize on for locking on the current session.
17.      * <p>In many cases, the HttpSession reference itself is a safe mutex
18.      * as well, since it will always be the same object reference for the
19.      * same active logical session. However, this is not guaranteed across
20.      * different servlet containers; the only 100% safe way is a session mutex.
21.      * @see org.springframework.web.servlet.mvc.AbstractController#handleRequestInternal
22.      * @see org.springframework.web.util.HttpSessionMutexListener
23.      * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
24.      */  
25. public final void setSynchronizeOnSession(boolean synchronizeOnSession) {  
26. this.synchronizeOnSession = synchronizeOnSession;  
27.     }  
28.   
29. /**
30.      * Return whether controller execution should be synchronized on the session.
31.      */  
32. public final boolean isSynchronizeOnSession() {  
33. return this.synchronizeOnSession;  
34.     }  
35.   
36.   
37. public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)  
38. throws Exception {  
39.   
40. // Delegate to WebContentGenerator for checking and preparing.  
41. this instanceof LastModified);  
42.   
43. // Execute handleRequestInternal in synchronized block if required.  
44. if (this.synchronizeOnSession) {  
45. false);  
46. if (session != null) {  
47.                 Object mutex = WebUtils.getSessionMutex(session);  
48. synchronized (mutex) {  
49. return handleRequestInternal(request, response);  
50.                 }  
51.             }  
52.         }  
53.           
54. return handleRequestInternal(request, response);  
55.     }  
56.   
57. /**
58.      * Template method. Subclasses must implement this.
59.      * The contract is the same as for <code>handleRequest</code>.
60.      * @see #handleRequest
61.      */  
62. protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  
63. throws Exception;  
64.   
65. }

再看一下继承了AbstractController的MultiActionController,MultiActionController中有对AbstractController的handleRequestInternal的实现



[java]  view plain  copy


 

1. protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  
2. throws Exception {  
3. try {  
4. this.methodNameResolver.getHandlerMethodName(request);  
5. return invokeNamedMethod(methodName, request, response);  
6.         }  
7. catch (NoSuchRequestHandlingMethodException ex) {  
8. return handleNoSuchRequestHandlingMethod(ex, request, response);  
9.         }  
10.     }


可以看出在MultiActionController的handleRequestInternal方法中分为两步,第一步是找寻执行该请求的方法名,第二步是调用invokeNamedMethod方法。


invokeNamedMethod方法源码


[java]  view plain  copy


 

1. protected final ModelAndView invokeNamedMethod(  
2. throws Exception {  
3.   
4. this.handlerMethodMap.get(methodName);  
5. if (method == null) {  
6. throw new NoSuchRequestHandlingMethodException(methodName, getClass());  
7.         }  
8.   
9. try {  
10.             Class[] paramTypes = method.getParameterTypes();  
11. new ArrayList<Object>(4);  
12.             params.add(request);  
13.             params.add(response);  
14.   
15. if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {  
16. false);  
17. if (session == null) {  
18. throw new HttpSessionRequiredException(  
19. "Pre-existing session required for handler method '" + methodName + "'");  
20.                 }  
21.                 params.add(session);  
22.             }  
23.   
24. // If last parameter isn't of HttpSession type, it's a command.  
25. if (paramTypes.length >= 3 &&  
26. 1].equals(HttpSession.class)) {  
27. 1]);  
28.                 params.add(command);  
29.                 bind(request, command);  
30.             }  
31. //执行该方法  
32. this.delegate, params.toArray(new Object[params.size()]));  
33. return massageReturnValueIfNecessary(returnValue);  
34.         }  
35. catch (InvocationTargetException ex) {  
36. // The handler method threw an exception.  
37. return handleException(request, response, ex.getTargetException());  
38.         }  
39. catch (Exception ex) {  
40. // The binding process threw an exception.  
41. return handleException(request, response, ex);  
42.         }  
43.     }


根据方法名在MultiActionController的方法集合属性handlerMethodMap中寻找对应的方法对象,然后执行该方法对象,执行该方法对象后获得一个object的返回值,通过massageReturnValueIfNecessary方法判断这个返回值的类型,如果这个值的返回类型是ModelAndView类型,就返回ModelAndView。到此我们找到响应请求的方法并执行获得了返回值。

虽然总体走完了,但是有两个地方还没有说,1如何根据用户发来的url请求来确定url中哪一段是执行该请求的方法名;2.确定方法名后是怎么找到该方法的。
MultiActionController中有一个构造函数,registerHandlerMethods(this.delegate);方法就是对我们所写的controller中的方法的注册。


[java]  view plain  copy


 


    1. public MultiActionController() {  
    2. this.delegate = this;  
    3. this.delegate);  
    4. // We'll accept no handler methods found here - a delegate might be set later on.  
    5. }


    registerHandlerMethods方法


    this.delegate其实就是继承了MultiActionController的控制对象,比如HelloWorld继承了MultiActionController,那么传过来的就是HelloWorld对象,就会将HelloWorld对象中的所有方法放到MultiActionController的handlerMethodMap属性中去了。


    [java]  view plain  copy


     

     
     
    1. private void registerHandlerMethods(Object delegate) {  
    2. this.handlerMethodMap.clear();  
    3. this.lastModifiedMethodMap.clear();  
    4. this.exceptionHandlerMap.clear();  
    5.   
    6. // Look at all methods in the subclass, trying to find  
    7. // methods that are validators according to our criteria  
    8.     Method[] methods = delegate.getClass().getMethods();  
    9. for (Method method : methods) {  
    10. // We're looking for methods with given parameters.  
    11. if (isExceptionHandlerMethod(method)) {  
    12.             registerExceptionHandlerMethod(method);  
    13.         }  
    14. else if (isHandlerMethod(method)) {  
    15.             registerHandlerMethod(method);  
    16.             registerLastModifiedMethodIfExists(delegate, method);  
    17.         }  
    18.     }  
    19. }

    在配置文件中有这样一段代码


    [html]  view plain  copy


     

    1. <!-- 在url中对应具体的方法,通过m后面带的参数来确定方法 -->  
    2. <bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">      
    3. <property name="paramName"><value>m</value></property>     
    4. <property name="defaultMethodName"><value>execute</value></property>  
    5. </bean>

    ParameterMethodNameResolver这个类的作用就是根据url链接中带的参数来确定执行该url的方法名是什么。在ioc容器初始ParameterMethodNameResolver的时候,容器会将“m”这个参数赋值给ParameterMethodNameResolver的属性paramName,然后ParameterMethodNameResolver会根据url中m后面跟的参数来获取方法名



    [java]  view plain  copy


     
        
     
    1. public String getHandlerMethodName(HttpServletRequest request) throws NoSuchRequestHandlingMethodException {  
    2. null;  
    3.   
    4. // Check parameter names where the very existence of each parameter  
    5. // means that a method of the same name should be invoked, if any.  
    6. if (this.methodParamNames != null) {  
    7. for (String candidate : this.methodParamNames) {  
    8. if (WebUtils.hasSubmitParameter(request, candidate)) {  
    9.                     methodName = candidate;  
    10. if (logger.isDebugEnabled()) {  
    11. "Determined handler method '" + methodName +  
    12. "' based on existence of explicit request parameter of same name");  
    13.                     }  
    14. break;  
    15.                 }  
    16.             }  
    17.         }  
    18.   
    19. // Check parameter whose value identifies the method to invoke, if any.  
    20. if (methodName == null && this.paramName != null) {  
    21. this.paramName);  
    22. if (methodName != null) {  
    23. if (logger.isDebugEnabled()) {  
    24. "Determined handler method '" + methodName +  
    25. "' based on value of request parameter '" + this.paramName + "'");  
    26.                 }  
    27.             }  
    28.         }  
    29.   
    30. if (methodName != null && this.logicalMappings != null) {  
    31. // Resolve logical name into real method name, if appropriate.  
    32.             String originalName = methodName;  
    33. this.logicalMappings.getProperty(methodName, methodName);  
    34. if (logger.isDebugEnabled()) {  
    35. "Resolved method name '" + originalName + "' to handler method '" + methodName + "'");  
    36.             }  
    37.         }  
    38.   
    39. if (methodName != null && !StringUtils.hasText(methodName)) {  
    40. if (logger.isDebugEnabled()) {  
    41. "Method name '" + methodName + "' is empty: treating it as no method name found");  
    42.             }  
    43. null;  
    44.         }  
    45.   
    46. if (methodName == null) {  
    47. if (this.defaultMethodName != null) {  
    48. // No specific method resolved: use default method.  
    49. this.defaultMethodName;  
    50. if (logger.isDebugEnabled()) {  
    51. "Falling back to default handler method '" + this.defaultMethodName + "'");  
    52.                 }  
    53.             }  
    54. else {  
    55. // If resolution failed completely, throw an exception.  
    56. throw new NoSuchRequestHandlingMethodException(request);  
    57.             }  
    58.         }  
    59.   
    60. return methodName;  
    61.     }


    当找到了方法名后,就会去MultiActionController属性handlerMethodMap中根据方法名找方法对象。再执行这个方法就好了。

    再来看看是如何从handlerMethodMap集合中找到方法并执行方法的


    [java]  view plain  copy


     

    1. protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  
    2. throws Exception {  
    3. try {  
    4. this.methodNameResolver.getHandlerMethodName(request);  
    5. return invokeNamedMethod(methodName, request, response);  
    6.         }  
    7. catch (NoSuchRequestHandlingMethodException ex) {  
    8. return handleNoSuchRequestHandlingMethod(ex, request, response);  
    9.         }  
    10.     }


    [java]  view plain  copy


     

     
     
    1. protected final ModelAndView invokeNamedMethod(  
    2. throws Exception {  
    3.   
    4. this.handlerMethodMap.get(methodName);  
    5. if (method == null) {  
    6. throw new NoSuchRequestHandlingMethodException(methodName, getClass());  
    7.         }  
    8.   
    9. try {  
    10.             Class[] paramTypes = method.getParameterTypes();  
    11. new ArrayList<Object>(4);  
    12.             params.add(request);  
    13.             params.add(response);  
    14.   
    15. if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {  
    16. false);  
    17. if (session == null) {  
    18. throw new HttpSessionRequiredException(  
    19. "Pre-existing session required for handler method '" + methodName + "'");  
    20.                 }  
    21.                 params.add(session);  
    22.             }  
    23.   
    24. // If last parameter isn't of HttpSession type, it's a command.  
    25. if (paramTypes.length >= 3 &&  
    26. 1].equals(HttpSession.class)) {  
    27. 1]);  
    28.                 params.add(command);  
    29.                 bind(request, command);  
    30.             }  
    31.   
    32. this.delegate, params.toArray(new Object[params.size()]));  
    33. return massageReturnValueIfNecessary(returnValue);  
    34.         }  
    35. catch (InvocationTargetException ex) {  
    36. // The handler method threw an exception.  
    37. return handleException(request, response, ex.getTargetException());  
    38.         }  
    39. catch (Exception ex) {  
    40. // The binding process threw an exception.  
    41. return handleException(request, response, ex);  
    42.         }  
    43.     }


    哎,本来是想春节之前将SpringMVC源码系列写完的,看是写不完了,还有ViewandResolve没有写,最近心境没有前一段时间平静,被外物所扰。2015年过的太平淡,感觉很重要的一年什么都没有留下,只能说很遗憾。在2016年一定要留下一些值得回味的东西,2016年不说要有多高大上,但一定要把基础打捞,框架什么的一定要很熟很熟。