天天看點

第四章 SpringMVC之HandlerAdapter解析

          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,就是我們自己寫的控制器

package com.wangbiao.springMVC;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

public class HelloWorld extends  MultiActionController{

	public ModelAndView sayHelloWorld(HttpServletRequest request, HttpServletResponse response) {
		String param = request.getParameter("param");
		System.out.println("springMVC測試:helloWorld;"+param);
		ModelAndView mv = new ModelAndView();
		mv.addObject("content", "springMVC HelloWorld:"+param);
		mv.setViewName("springMVC/helloWorld");
		ServletContext ctx = this.getServletContext();	
		return mv;
	}

}
           

 2.SpringMVC配置檔案

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
    xmlns="http://www.springframework.org/schema/beans"    
    xmlns:mvc="http://www.springframework.org/schema/mvc"    
    xmlns:context="http://www.springframework.org/schema/context"    
    xmlns:aop="http://www.springframework.org/schema/aop"    
    xmlns:tx="http://www.springframework.org/schema/tx"    
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
        http://www.springframework.org/schema/mvc  
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd  
        http://www.springframework.org/schema/context  
        http://www.springframework.org/schema/context/spring-context-3.0.xsd   
        http://www.springframework.org/schema/aop    
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd   
        http://www.springframework.org/schema/tx   
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> 
        <!-- handlerMapping  -->
       <bean id="beanNameUrlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> 
	   <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	             <property name="mappings">
	                          <props>
	                                 <prop key="/springMVC.d">/HelloWorld</prop>
	                          </props>
	             </property>
	</bean>
		
	<bean name="/HelloWorld" class="com.wangbiao.springMVC.HelloWorld">
	             <property name="methodNameResolver">
	                           <ref local="methodNameResolver"/>
	             </property>
	</bean>
	<!-- 在url中對應具體的方法,通過m後面帶的參數來确定方法 -->
	<bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">	
	            <property name="paramName"><value>m</value></property>   
		        <property name="defaultMethodName"><value>execute</value></property>
	</bean>
	
	  <!--視圖解析器-->  
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
            <!-- webroot到一指定檔案夾檔案路徑 -->  
            <property name="prefix" value="/"/>  
            <!-- 視圖名稱字尾  -->  
            <property name="suffix" value=".jsp"/>  
            </bean>            
	</beans>
           

下面是源碼

1.DispatcherServlet注冊HandlerAdapter。DispatcherServlet的initHandlerAdapters方法,紅色标記的部分是關鍵。由于在配置檔案中沒有對HandlerAdapter的相關配置,是以DispatcherServlet擷取到的HandlerAdapter是三個預設的HandlerAdapter對象,分别是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,并将這三個對象存入handlerAdapter屬性中去。

private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;

		if (this.detectAllHandlerAdapters) {
			// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
				// We keep HandlerAdapters in sorted order.
				OrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerAdapter later.
			}
		}

		// Ensure we have at least some HandlerAdapters, by registering
		// default HandlerAdapters if no other adapters are found.
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
			}
		}
	}
           

2.根據handlerMapping傳過來的Handler對象與DispatcherServlet集合屬性handlerAdapter中的HandlerAdapter一一比對,如果有支援Handler對象的HandlerAdapter,那麼HandlerAdapter就會調用自己的handle方法處理請求。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		int interceptorIndex = -1;

		try {
			ModelAndView mv;
			boolean errorView = false;

			try {
				processedRequest = checkMultipart(request);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest, false);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						String requestUri = urlPathHelper.getRequestUri(request);
						logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				// Apply preHandle methods of registered interceptors.
				HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
				if (interceptors != null) {
					for (int i = 0; i < interceptors.length; i++) {
						HandlerInterceptor interceptor = interceptors[i];
						if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
							triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
							return;
						}
						interceptorIndex = i;
					}
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				// Do we need view name translation?
				if (mv != null && !mv.hasView()) {
					mv.setViewName(getDefaultViewName(request));
				}

				// Apply postHandle methods of registered interceptors.
				if (interceptors != null) {
					for (int i = interceptors.length - 1; i >= 0; i--) {
						HandlerInterceptor interceptor = interceptors[i];
						interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
					}
				}
			}
			catch (ModelAndViewDefiningException ex) {
				logger.debug("ModelAndViewDefiningException encountered", ex);
				mv = ex.getModelAndView();
			}
			catch (Exception ex) {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(processedRequest, response, handler, ex);
				errorView = (mv != null);
			}

			// Did the handler return a view to render?
			if (mv != null && !mv.wasCleared()) {
				render(mv, processedRequest, response);
				if (errorView) {
					WebUtils.clearErrorRequestAttributes(request);
				}
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
							"': assuming HandlerAdapter completed request handling");
				}
			}

			// Trigger after-completion for successful outcome.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
		}

		catch (Exception ex) {
			// Trigger after-completion for thrown exception.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
			throw ex;
		}
		catch (Error err) {
			ServletException ex = new NestedServletException("Handler processing failed", err);
			// Trigger after-completion for thrown exception.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
			throw ex;
		}

		finally {
			// Clean up any resources used by a multipart request.
			if (processedRequest != request) {
				cleanupMultipart(processedRequest);
			}
		}
	}
           

getHandlerAdapter方法

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
			if (ha.supports(handler)) {
				return ha;
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: Does your handler implement a supported interface like Controller?");
	}
           

HandlerAdapter接口

/*
 * Copyright 2002-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * MVC framework SPI interface, allowing parameterization of core MVC workflow.
 *
 * <p>Interface that must be implemented for each handler type to handle a request.
 * This interface is used to allow the {@link DispatcherServlet} to be indefinitely
 * extensible. The DispatcherServlet accesses all installed handlers through this
 * interface, meaning that it does not contain code specific to any handler type.
 *
 * <p>Note that a handler can be of type <code>Object</code>. This is to enable
 * handlers from other frameworks to be integrated with this framework without
 * custom coding, as well as to allow for annotation handler objects that do
 * not obey any specific Java interface.
 *
 * <p>This interface is not intended for application developers. It is available
 * to handlers who want to develop their own web workflow.
 *
 * <p>Note: HandlerAdaptger implementators may implement the
 * {@link org.springframework.core.Ordered} interface to be able to specify a
 * sorting order (and thus a priority) for getting applied by DispatcherServlet.
 * Non-Ordered instances get treated as lowest priority.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
 * @see org.springframework.web.servlet.handler.SimpleServletHandlerAdapter
 */
public interface HandlerAdapter {
	
	/**
	 * Given a handler instance, return whether or not this HandlerAdapter can
	 * support it. Typical HandlerAdapters will base the decision on the handler
	 * type. HandlerAdapters will usually only support one handler type each.
	 * <p>A typical implementation:
	 * <p><code>
	 * return (handler instanceof MyHandler);
	 * </code>
	 * @param handler handler object to check
	 * @return whether or not this object can use the given handler
	 */
	boolean supports(Object handler); 
	
	/**
	 * Use the given handler to handle this request.
	 * The workflow that is required may vary widely.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler handler to use. This object must have previously been passed
	 * to the <code>supports</code> method of this interface, which must have
	 * returned <code>true</code>.
	 * @throws Exception in case of errors
	 * @return ModelAndView object with the name of the view and the required
	 * model data, or <code>null</code> if the request has been handled directly
	 */
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	/**
	 * Same contract as for HttpServlet's <code>getLastModified</code> method.
	 * Can simply return -1 if there's no support in the handler class.
	 * @param request current HTTP request
	 * @param handler handler to use
	 * @return the lastModified value for the given handler
	 * @see javax.servlet.http.HttpServlet#getLastModified
	 * @see org.springframework.web.servlet.mvc.LastModified#getLastModified
	 */
	long getLastModified(HttpServletRequest request, Object handler);

}
           

再來看一下自己寫的控制器HelloWorld繼承了MultiActionController。MultiActionController又繼承了AbstractController,AbstractController實作了Controller。這樣就看DispatcherServlet屬性中的HandlerApater誰支援Controller類型的處理器了。在運作的過程中發現SimpleControllerHandlerAdapter是支援Controller類型的控制器的。

來看一下SimpleControllerHandlerAdapter的代碼

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return ((Controller) handler).handleRequest(request, response);
	}

	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}
           

再看一下Controller源碼,Controller接口隻有一個handleRequest方法

public interface Controller {

	/**
	 * Process the request and return a ModelAndView object which the DispatcherServlet
	 * will render. A <code>null</code> return value is not an error: It indicates that
	 * this object completed request processing itself, thus there is no ModelAndView
	 * to render.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @return a ModelAndView to render, or <code>null</code> if handled directly
	 * @throws Exception in case of errors
	 */
	ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;

}
           

再看看實作了Controller接口的AbstractController類

public abstract class AbstractController extends WebContentGenerator implements Controller {

	private boolean synchronizeOnSession = false;


	/**
	 * Set if controller execution should be synchronized on the session,
	 * to serialize parallel invocations from the same client.
	 * <p>More specifically, the execution of the <code>handleRequestInternal</code>
	 * method will get synchronized if this flag is "true". The best available
	 * session mutex will be used for the synchronization; ideally, this will
	 * be a mutex exposed by HttpSessionMutexListener.
	 * <p>The session mutex is guaranteed to be the same object during
	 * the entire lifetime of the session, available under the key defined
	 * by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a
	 * safe reference to synchronize on for locking on the current session.
	 * <p>In many cases, the HttpSession reference itself is a safe mutex
	 * as well, since it will always be the same object reference for the
	 * same active logical session. However, this is not guaranteed across
	 * different servlet containers; the only 100% safe way is a session mutex.
	 * @see org.springframework.web.servlet.mvc.AbstractController#handleRequestInternal
	 * @see org.springframework.web.util.HttpSessionMutexListener
	 * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
	 */
	public final void setSynchronizeOnSession(boolean synchronizeOnSession) {
		this.synchronizeOnSession = synchronizeOnSession;
	}

	/**
	 * Return whether controller execution should be synchronized on the session.
	 */
	public final boolean isSynchronizeOnSession() {
		return this.synchronizeOnSession;
	}


	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		// Delegate to WebContentGenerator for checking and preparing.
		checkAndPrepare(request, response, this instanceof LastModified);

		// Execute handleRequestInternal in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return handleRequestInternal(request, response);
				}
			}
		}
		
		return handleRequestInternal(request, response);
	}

	/**
	 * Template method. Subclasses must implement this.
	 * The contract is the same as for <code>handleRequest</code>.
	 * @see #handleRequest
	 */
	protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
	    throws Exception;

}
           

再看一下繼承了AbstractController的MultiActionController,MultiActionController中有對AbstractController的handleRequestInternal的實作

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		try {
			String methodName = this.methodNameResolver.getHandlerMethodName(request);
			return invokeNamedMethod(methodName, request, response);
		}
		catch (NoSuchRequestHandlingMethodException ex) {
			return handleNoSuchRequestHandlingMethod(ex, request, response);
		}
	}
           

可以看出在MultiActionController的handleRequestInternal方法中分為兩步,第一步是找尋執行該請求的方法名,第二步是調用invokeNamedMethod方法。

invokeNamedMethod方法源碼

protected final ModelAndView invokeNamedMethod(
			String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {

		Method method = this.handlerMethodMap.get(methodName);
		if (method == null) {
			throw new NoSuchRequestHandlingMethodException(methodName, getClass());
		}

		try {
			Class[] paramTypes = method.getParameterTypes();
			List<Object> params = new ArrayList<Object>(4);
			params.add(request);
			params.add(response);

			if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {
				HttpSession session = request.getSession(false);
				if (session == null) {
					throw new HttpSessionRequiredException(
							"Pre-existing session required for handler method '" + methodName + "'");
				}
				params.add(session);
			}

			// If last parameter isn't of HttpSession type, it's a command.
			if (paramTypes.length >= 3 &&
					!paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {
				Object command = newCommandObject(paramTypes[paramTypes.length - 1]);
				params.add(command);
				bind(request, command);
			}
                        //執行該方法
			Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()]));
			return massageReturnValueIfNecessary(returnValue);
		}
		catch (InvocationTargetException ex) {
			// The handler method threw an exception.
			return handleException(request, response, ex.getTargetException());
		}
		catch (Exception ex) {
			// The binding process threw an exception.
			return handleException(request, response, ex);
		}
	}
           

根據方法名在MultiActionController的方法集合屬性handlerMethodMap中尋找對應的方法對象,然後執行該方法對象,執行該方法對象後獲得一個object的傳回值,通過massageReturnValueIfNecessary方法判斷這個傳回值的類型,如果這個值的傳回類型是ModelAndView類型,就傳回ModelAndView。到此我們找到響應請求的方法并執行獲得了傳回值。

雖然總體走完了,但是有兩個地方還沒有說,1如何根據使用者發來的url請求來确定url中哪一段是執行該請求的方法名;2.确定方法名後是怎麼找到該方法的。

MultiActionController中有一個構造函數,registerHandlerMethods(this.delegate);方法就是對我們所寫的controller中的方法的注冊。

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

registerHandlerMethods方法

this.delegate其實就是繼承了MultiActionController的控制對象,比如HelloWorld繼承了MultiActionController,那麼傳過來的就是HelloWorld對象,就會将HelloWorld對象中的所有方法放到MultiActionController的handlerMethodMap屬性中去了。

private void registerHandlerMethods(Object delegate) {
		this.handlerMethodMap.clear();
		this.lastModifiedMethodMap.clear();
		this.exceptionHandlerMap.clear();

		// Look at all methods in the subclass, trying to find
		// methods that are validators according to our criteria
		Method[] methods = delegate.getClass().getMethods();
		for (Method method : methods) {
			// We're looking for methods with given parameters.
			if (isExceptionHandlerMethod(method)) {
				registerExceptionHandlerMethod(method);
			}
			else if (isHandlerMethod(method)) {
				registerHandlerMethod(method);
				registerLastModifiedMethodIfExists(delegate, method);
			}
		}
	}
           

在配置檔案中有這樣一段代碼

<!-- 在url中對應具體的方法,通過m後面帶的參數來确定方法 -->
	<bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">	
	            <property name="paramName"><value>m</value></property>   
		        <property name="defaultMethodName"><value>execute</value></property>
	</bean>
           

ParameterMethodNameResolver這個類的作用就是根據url連結中帶的參數來确定執行該url的方法名是什麼。在ioc容器初始ParameterMethodNameResolver的時候,容器會将“m”這個參數指派給ParameterMethodNameResolver的屬性paramName,然後ParameterMethodNameResolver會根據url中m後面跟的參數來擷取方法名

public String getHandlerMethodName(HttpServletRequest request) throws NoSuchRequestHandlingMethodException {
		String methodName = null;

		// Check parameter names where the very existence of each parameter
		// means that a method of the same name should be invoked, if any.
		if (this.methodParamNames != null) {
			for (String candidate : this.methodParamNames) {
				if (WebUtils.hasSubmitParameter(request, candidate)) {
					methodName = candidate;
					if (logger.isDebugEnabled()) {
						logger.debug("Determined handler method '" + methodName +
								"' based on existence of explicit request parameter of same name");
					}
					break;
				}
			}
		}

		// Check parameter whose value identifies the method to invoke, if any.
		if (methodName == null && this.paramName != null) {
			methodName = request.getParameter(this.paramName);
			if (methodName != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Determined handler method '" + methodName +
							"' based on value of request parameter '" + this.paramName + "'");
				}
			}
		}

		if (methodName != null && this.logicalMappings != null) {
			// Resolve logical name into real method name, if appropriate.
			String originalName = methodName;
			methodName = this.logicalMappings.getProperty(methodName, methodName);
			if (logger.isDebugEnabled()) {
				logger.debug("Resolved method name '" + originalName + "' to handler method '" + methodName + "'");
			}
		}

		if (methodName != null && !StringUtils.hasText(methodName)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Method name '" + methodName + "' is empty: treating it as no method name found");
			}
			methodName = null;
		}

		if (methodName == null) {
			if (this.defaultMethodName != null) {
				// No specific method resolved: use default method.
				methodName = this.defaultMethodName;
				if (logger.isDebugEnabled()) {
					logger.debug("Falling back to default handler method '" + this.defaultMethodName + "'");
				}
			}
			else {
				// If resolution failed completely, throw an exception.
				throw new NoSuchRequestHandlingMethodException(request);
			}
		}

		return methodName;
	}
           

當找到了方法名後,就會去MultiActionController屬性handlerMethodMap中根據方法名找方法對象。再執行這個方法就好了。

再來看看是如何從handlerMethodMap集合中找到方法并執行方法的

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		try {
			String methodName = this.methodNameResolver.getHandlerMethodName(request);
			return invokeNamedMethod(methodName, request, response);
		}
		catch (NoSuchRequestHandlingMethodException ex) {
			return handleNoSuchRequestHandlingMethod(ex, request, response);
		}
	}
           
protected final ModelAndView invokeNamedMethod(
			String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {

		Method method = this.handlerMethodMap.get(methodName);
		if (method == null) {
			throw new NoSuchRequestHandlingMethodException(methodName, getClass());
		}

		try {
			Class[] paramTypes = method.getParameterTypes();
			List<Object> params = new ArrayList<Object>(4);
			params.add(request);
			params.add(response);

			if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {
				HttpSession session = request.getSession(false);
				if (session == null) {
					throw new HttpSessionRequiredException(
							"Pre-existing session required for handler method '" + methodName + "'");
				}
				params.add(session);
			}

			// If last parameter isn't of HttpSession type, it's a command.
			if (paramTypes.length >= 3 &&
					!paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {
				Object command = newCommandObject(paramTypes[paramTypes.length - 1]);
				params.add(command);
				bind(request, command);
			}

			Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()]));
			return massageReturnValueIfNecessary(returnValue);
		}
		catch (InvocationTargetException ex) {
			// The handler method threw an exception.
			return handleException(request, response, ex.getTargetException());
		}
		catch (Exception ex) {
			// The binding process threw an exception.
			return handleException(request, response, ex);
		}
	}
           

哎,本來是想春節之前将SpringMVC源碼系列寫完的,看是寫不完了,還有ViewandResolve沒有寫,最近心境沒有前一段時間平靜,被外物所擾。2015年過的太平淡,感覺很重要的一年什麼都沒有留下,隻能說很遺憾。在2016年一定要留下一些值得回味的東西,2016年不說要有多高大上,但一定要把基礎打撈,架構什麼的一定要很熟很熟。

 HandlerAdapter,大家都叫它适配處理器,就是适配不同的處理器,将他們封裝起來調用同一個借口方法,這樣DispatcherServlet就隻需要調用接口方法,而不需要在DispatcherServlet判斷調用哪一個具體的HandlerAdapter的實作類了。

         當時看到自己項目裡面的所有的處理器都是實作了MultiActionController的Controller,再去看MultiActionController的源碼時,發現MultiActionController實作了Controller接口,Controller接口隻有一個handleRequest方法,我想DispatcherServlet直接用Controller的handleRequest方法執行具體請求就行了,何必還要用HandlerAdapter将Controller封裝起來,再在HandlerAdapter的handle方法裡執行Controller的handleRequest方法呢,這不是多此一舉?

        隻怪自己目光短淺,由于用的是配置的方式來做項目的,而且平時自己寫的Controller隻繼承了MultiActionController,以為Controller接口就是所有的處理器的接口,眼裡就隻有Controller了。

        今天再來看源碼,發現處理器根本就不隻有Controller這一種。還有HttpRequestHandler,Servlet等處理器。下面來介紹一下幾種擴充卡對應的處理器以及這些處理器的作用\

        1. AnnotationMethodHandlerAdapter主要是适配注解類處理器,注解類處理器就是我們經常使用的@Controller的這類處理器

        2. HttpRequestHandlerAdapter主要是适配靜态資源處理器,靜态資源處理器就是實作了HttpRequestHandler接口的處理器,這類處理器的作用是處理通過SpringMVC來通路的靜态資源的請求。        

        3.SimpleControllerHandlerAdapter是Controller處理擴充卡,适配實作了Controller接口或Controller接口子類的處理器,比如我們經常自己寫的Controller來繼承MultiActionController,那麼自己寫的這些Controller就會由SimpleControllerHandlerAdapter來适配

        4.SimpleServletHandlerAdapter是Servlet處理擴充卡,适配實作了Servlet接口或Servlet的子類的處理器,我們不僅可以在web.xml裡面配置Servlet,其實也可以用SpringMVC來配置Servlet,不過這個擴充卡很少用到,而且SpringMVC預設的擴充卡沒有他,預設的是前面的三種。

        适配處理器當然用到了擴充卡模式。

        今天終于将這個問題弄懂了,隻怪當初看源碼的時候接觸的太單一了,如果大家覺得有什麼不妥的地方,歡迎大家拍磚

繼續閱讀