SpringMVC組件 源碼閱讀(SpringMVC的設計與實現)

1 SpringMVC應用場景

在使用 SpringMVC 時,除了要在 web.xml 中配置 ContextLoaderListener 外,還要對 DispatcherServlet 進行配置。作爲一個 Servlet,這個 DispatcherServlet 實現的是 Sun 的 J2EE核心模式 中的 前端控制器模式(Front Controller), 作爲一個前端控制器,所有的 Web請求 都需要通過它來進行轉發、匹配、數據處理,然後轉由頁面進行展現,因此這個 DispatcerServlet 可以看成是 SpringMVC實現 中最爲核心的部分。

在 SpringMVC 中,對於不同的 Web請求 的映射需求,SpringMVC 提供了不同的 HandlerMapping 的實現,可以讓應用開發選取不同的映射策略。DispatcherSevlet 默認了 BeanNameUrlHandlerMapping 作爲映射策略實現。除了映射策略可以定製外,SpringMVC 還提供了各種 Controller 的實現來供應用擴展和使用,以應對不同的控制器使用場景,這些 Controller控制器 需要實現 handleRequest()接口方法,並返回 ModelAndView對象。SpringMVC 還提供了各種視圖實現,比如常用的 JSP視圖。除此之外,SpringMVC 還提供了攔截器供應用使用,允許應用對 Web請求 進行攔截,以及前置處理和後置處理。

2 SpringMVC設計概覽

在完成對 ContextLoaderListener 的初始化以後,Web容器 開始初始化 DispatcherServlet,這個初始化的啓動與在 web.xml 中對載入次序的定義有關。DispatcherServlet 會建立自己的上下文來持有SpringMVC 的 Bean對象,在建立這個自己持有的 IoC容器 時,會從 ServletContext 中得到根上下文作爲 DispatcherServlet 持有上下文的雙親上下文。有了這個根上下文,再對自己持有的上下文進行初始化,最後把自己持有的這個上下文保存到 ServletContext 中,供以後檢索和使用。

爲了解這個過程,可以從 DispatcherServlet 的父類 FrameworkServlet 的代碼入手,去探尋 DispatcherServlet 的啓動過程,它同時也是 SpringMVC 的啓動過程。ApplicationContext 的創建過程和 ContextLoader 創建根上下文的過程有許多類似的地方。下面來看一下這個 DispatcherServlet類 的繼承關係。
在這裏插入圖片描述
DispatcherServlet 通過繼承 FrameworkServlet 和 HttpServletBean 而繼承了 HttpServlet,通過使用Servlet API 來對 HTTP請求 進行響應,成爲 SpringMVC 的前端處理器,同時成爲 MVC模塊 與 Web容器 集成的處理前端。

DispatcherServlet 的工作大致可以分爲兩個部分:一個是初始化部分,由 initServletBean()方法 啓動,通過 initWebApplicationContext()方法 最終調用 DispatcherServlet 的 initStrategies()方法,在這個方法裏,DispatcherServlet 對 MVC模塊 的其他部分進行了初始化,比如 handlerMapping、ViewResolver 等;另一個是對 HTTP請求 進行響應,作爲一個 Servlet,Web容器 會調用 Servlet 的doGet() 和 doPost()方法,在經過 FrameworkServlet 的 processRequest() 簡單處理後,會調用 DispatcherServlet 的 doService()方法,在這個方法調用中封裝了 doDispatch(),這個 doDispatch() 是 Dispatcher 實現 MVC模式 的主要部分,下圖爲 DispatcherServlet 的處理過程時序圖。
DispatcherServlet的處理過程

3 DispatcherServlet的啓動和初始化

前面大致描述了 SpringMVC 的工作流程,下面看一下 DispatcherServlet 的啓動和初始化的代碼設計及實現。

作爲 Servlet,DispatcherServlet 的啓動與 Servlet 的啓動過程是相聯繫的。在 Servlet 的初始化過程中,Servlet 的 init()方法 會被調用,以進行初始化,DispatcherServlet 的基類 HttpServletBean 實現了該方法。在初始化開始時,需要讀取配置在 ServletContext 中的 Bean屬性參數,這些屬性參數設置在 web.xml 的 Web容器初始化參數 中。使用編程式的方式來設置這些 Bean屬性,在這裏可以看到對 PropertyValues 和 BeanWrapper 的使用。對於這些和依賴注人相關的類的使用,在分析 IoC容器 的初始化時,尤其是在依賴注入實現分析時,有過“親密接觸”。只是這裏的依賴注人是與 Web容器 初始化相關的。

接着會執行 DispatcherServlet 持有的 IoC容器 的初始化過程,在這個初始化過程中,一個新的上下文被建立起來,這個 DispatcherServlet 持有的上下文被設置爲根上下文的子上下文。一個 Web應用 中可以容納多個 Servlet 存在;與此相對應,對於應用在 Web容器 中的上下體系,一個根上下文可以作爲許多 Servlet上下文 的雙親上下文。瞭解 IoC 工作原理的讀者知道,在向 IoC容器 getBean() 時,IoC容器 會首先向其雙親上下文去 getBean(),也就是說,在根上下文中定義的 Bean 是可以被各個 Servlet 持有的上下文得到和共享的。DispatcherServlet 持有的 上下文被建立起來以後,也需要和其他 IoC容器 一樣完成初始化,這個初始化也是通過 refresh()方法 來完成的。最後,DispatcherServlet 給這個自己持有的上下文命名,並把它設置到 Web容器 的上下文中,這個名稱和在 web.xml 中設置的 DispatcherServlet 的 Servlet名稱 有關,從而保證了這個上下文在 Web環境上下文體系 中的唯一性。

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {

	public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		// 獲取 Servlet 的初始化參數,對 bean屬性 進行配置
		try {
			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
			ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
			initBeanWrapper(bw);
			bw.setPropertyValues(pvs, true);
		}
		catch (BeansException ex) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}

		// 這個方法會調用子類的實現,進行具體的初始化
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}
}


public abstract class FrameworkServlet extends HttpServletBean {

	/** 此 servlet 的 WebApplicationContext */
	private WebApplicationContext webApplicationContext;

	/** 我們是否應該將當前 Servlet 的上下文 webApplicationContext 設爲 ServletContext 的屬性 */
	private boolean publishContext = true;

	public FrameworkServlet() {
	}
	
	public FrameworkServlet(WebApplicationContext webApplicationContext) {
		this.webApplicationContext = webApplicationContext;
	}
	
	/**
	 * 覆蓋了父類 HttpServletBean 的空實現
	 */
	@Override
	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
		if (this.logger.isInfoEnabled()) {
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// 初始化上下文
			this.webApplicationContext = initWebApplicationContext();
			initFrameworkServlet();
		}
		catch (ServletException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}
		catch (RuntimeException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (this.logger.isInfoEnabled()) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}

	/**
	 * 爲這個 Servlet 初始化一個公共的 WebApplicationContext實例
	 */
	protected WebApplicationContext initWebApplicationContext() {
		// 獲取根上下文作爲當前 MVC上下文 的雙親上下文,這個根上下文保存在 ServletContext 中
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			// 可以在本對象被構造時注入一個 webApplicationContext實例
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// 上下文尚未刷新 -> 提供諸如設置父上下文、設置應用程序上下文id等服務
					if (cwac.getParent() == null) {
						// 上下文實例在沒有顯式父實例的情況下被注入 -> 
						// 將根上下文(如果有的話;可以爲空)設置爲父上下文
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// 在本對象被構造時沒有注入上下文實例 -> 
			// 查看是否已在 servlet上下文 中註冊了上下文實例。
			// 如果存在一個,則假定父上下文(如果有的話)已經被設置,
			// 並且用戶已經執行了任何初始化,例如設置上下文ID
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// 沒有爲此 servlet 定義上下文實例 -> 創建本地實例
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// 上下文不是支持刷新的 ConfigurableApplicationContext,或者
			// 在構造時注入的上下文已經完成刷新 -> 在此處手動觸發 onRefresh()方法
			onRefresh(wac);
		}

		if (this.publishContext) {
			// 把當前建立的上下文保存到 ServletContext 中,使用的屬性名是和 當前servlet名 相關的
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}
}

至此,這個 MVC 的上下文就建立起來了,具體取得根上下文的過程在 WebApplicationContextUtils 中實現。這個根上下文是 ContextLoader 設置到 ServletContext 中去的,使用的屬性是 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,ContextLoader 還對這個 IoC容器 的 Bean 配置文件進行了設置,默認的位置是在 /WEB-INF/applicationContext.xml文件 中。由於這個根上下文是 DispatcherServlet 建立的上下文的 雙親上下文,所以根上下文中管理的 Bean 也可以被 DispatcherServlet 的上下文使用。通過 getBean() 向 IoC容器 獲取 Bean 時,容器會先到它的 雙親IoC容器 中獲取。

/**
 * 這是一個封裝了很多靜態方法的抽象工具類,所以只能調用其靜態方法,
 * 不能對其進行實例化
 */
public abstract class WebApplicationContextUtils {
	/**
	 * 使用了 WebApplicationContext 的 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE屬性,獲取
	 * ServletContext 中的根上下文,這個屬性代表的根上下文在 ContextLoaderListener 初始化的
	 * 過程中被建立
	 */
	public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
		return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
	}

	/**
	 * 查找此 web應用程序 的自定義 WebApplicationContext
	 */
	public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
		Assert.notNull(sc, "ServletContext must not be null");
		Object attr = sc.getAttribute(attrName);
		if (attr == null) {
			return null;
		}
		if (attr instanceof RuntimeException) {
			throw (RuntimeException) attr;
		}
		if (attr instanceof Error) {
			throw (Error) attr;
		}
		if (attr instanceof Exception) {
			throw new IllegalStateException((Exception) attr);
		}
		if (!(attr instanceof WebApplicationContext)) {
			throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);
		}
		return (WebApplicationContext) attr;
	}
)

回到 FrameworkServlet 的實現中來看一下,DispatcherServlet 的上下文是怎樣建立的,這個建立過程與前面建立根上下文的過程非常類似。建立 DispatcherServlet 的上下文,需要把根上下文作爲參數傳遞給它。然後使用反射技術來實例化上下文對象,併爲它設置參數。根據默認的配置,這個上下文對象也是 XmlWebApplicationContext對象,這個類型是在 DEFAULT_CONTEXT_CLASS參數 中設置好並允許 BeanUtilis 使用的。在實例化結束後,需要爲這個上下文對象設置好一些基本的配置,這些配置包括它的雙親上下文、Bean配置文件 的位置等。完成這些配置以後,最後通過調用 IoC容器 的 refresh()方法 來完成 IoC容器 的最終初始化,這和前面我們對 IoC容器實現原理 的分析中所看到的 IoC容器初始化 的過程是一致的。

public abstract class FrameworkServlet extends HttpServletBean {

	/**
	 * 爲此 servlet 實例化一個 WebApplicationContext,可以是默認的 XmlWebApplicationContext,
	 * 也可以是用戶設置的自定義 Context上下文
	 */
	protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
		return createWebApplicationContext((ApplicationContext) parent);
	}

	protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		// 默認爲 XmlWebApplicationContext.class
		Class<?> contextClass = getContextClass();
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Servlet with name '" + getServletName() +
					"' will try to create custom WebApplicationContext context of class '" +
					contextClass.getName() + "'" + ", using parent context [" + parent + "]");
		}
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
		// 實例化需要的上下文對象,併爲其設置屬性
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
		// 這裏設置的 雙親上下文,就是在 ContextLoader 中建立的根上下文
		wac.setParent(parent);
		wac.setConfigLocation(getContextConfigLocation());

		// 配置並且刷新 WebApplicationContext對象
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// 應用程序上下文id 仍設置爲其原始默認值,如果該 id 不爲空的話
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				// 生成默認的 id
				ServletContext sc = getServletContext();
				if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
					// 當 Servlet <= 2.4:如果有,請使用 web.xml 中指定的名稱。
					String servletContextName = sc.getServletContextName();
					if (servletContextName != null) {
						wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName +
								"." + getServletName());
					}
					else {
						wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + getServletName());
					}
				}
				else {
					// Servlet 2.5 的 getContextPath 可用!
					wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
							ObjectUtils.getDisplayString(sc.getContextPath()) + "/" + getServletName());
				}
			}
		}

		// 設置其它配置信息
		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

		// 在刷新上下文的任何情況下,都將會調用 此wac 的 env的 initPropertySources()方法。
		// 在此處執行此方法,以確保在刷新上下文之前,servlet屬性源 已準備就緒
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment)env).initPropertySources(getServletContext(), getServletConfig());
		}

		postProcessWebApplicationContext(wac);

		applyInitializers(wac);

		// IoC容器 都是通過該方法完成 容器初始化的
		wac.refresh();
	}
}

這時候 DispatcherServlet 中的 IoC容器 已經建立起來了,這個 IoC容器 是 根上下文 的子容器。如果要查找一個由 DispatcherServlet 所持有的 IoC容器 來管理的 Bean,系統會首先到 根上下文 中去查找。如果查找不到,纔會到 DispatcherServlet 所管理的 IoC容器 去進行查找,這是由 IoC容器 的 getBean() 的實現來決定的。通過一系列在 Web容器 中執行的動作,在這個上下文體系建立和初始化完畢的基礎上,SpringMVC 就可以發揮其作用了。下面來分析一下 SpringMVC 的具體實現。

在前面分析 DispatchServlet 的初始化過程中可以看到,DispatchServlet 持有一個以自己的 Servlet名稱 命名的 IoC容器。這個 IoC容器 是一個 WebApplicationContext對象,這個 IoC容器 建立起來以後,意味着 DispatcherServlet 擁有自己的 Bean定義空間,這爲使用各個獨立的 XML文件 來配置 MVC 中各個 Bean 創造了條件。由於在初始化結束以後,與 Web容器 相關的加載過程實際上已經完成了,SpringMVC 的具體實現和普通的 Spring應用程序 的實現並沒有太大的差別。

在 DispatcherServlet 的初始化過程中,以對 HandlerMapping 的初始化調用作爲觸發點,瞭解 SpringMVC模塊 初始化的方法調用關係。這個調用關係最初是由 HttpServletBean 的 init()方法 觸發的,這個 HttpServletBean 是 HttpServlet 的子類。接着會在 HttpServletBean 的子類 FrameworkServlet 中對 IoC容器 完成初始化,在這個初始化方法中,會調用 DispatcherServlet 的 initStrategies()方法,該方法包括對各種 MVC框架 的實現元素,比如支持國際化的 LocalResolver、支持 request 映射的 HandlerMappings,以及視圖生成的 ViewResolver 等。由該方法啓動整個 SpringMVC框架 的初始化。

public class DispatcherServlet extends FrameworkServlet {
	/**
	 * 初始化此 servlet 使用的策略對象。
	 * 可以在子類中重寫,以便初始化進一步的策略對象(U8C)
	 */
	protected void initStrategies(ApplicationContext context) {
		// 請求解析
		initMultipartResolver(context);
		// 多語言,國際化
		initLocaleResolver(context);
		// 主題view層
		initThemeResolver(context);
		// 解析 url 和 Method 的對應關係
		initHandlerMappings(context);
		// 適配器匹配
		initHandlerAdapters(context);
		// 異常解析
		initHandlerExceptionResolvers(context);
		// 視圖轉發,根據視圖名字匹配到一個具體模板
		initRequestToViewNameTranslator(context);
		// 解析模板中的內容
		initViewResolvers(context);

		initFlashMapManager(context);
	}
}

對於具體的初始化過程,根據上面的方法名稱,很容易理解。以 HandlerMapping 爲例來說明這個 initHandlerMappings()過程。這裏的 Mapping關係 的作用是,爲 HTTP請求 找到相應的 Controller控制器,從而利用這些 控制器Controller 去完成設計好的數據處理工作。

HandlerMappings 完成對 MVC 中 Controller 的定義和配置,只不過在 Web 這個特定的應用環境中,這些控制器是與具體的 HTTP請求 相對應的。在 HandlerMapping初始化 的過程中,把在 Bean配置文件 中配置好的 HandlerMapping 從 IoC容器 中取得。

	/**
	 * 初始化此類使用的 HandlerMappings。
	 * 如果在 BeanFactory 中沒有爲此命名空間定義的 HandlerMapping bean,則默認爲 BeanNameUrlHandlerMapping
	 */
	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		// 這個 detectAllHandlerMappings 默認爲 true,表示從所有的 IoC容器 中獲取所有的HandlerMappings
		if (this.detectAllHandlerMappings) {
			// 查找所有的 HandlerMapping,從 應用上下文context 及其雙親上下文中
			Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
					context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<HandlerMapping>(
						matchingBeans.values());
				// 保持 HandlerMappings 的有序性
				OrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				// 根據名稱從當前的 IoC容器 中通過 getBean() 獲 取HandlerMapping
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME,
						HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// 忽略,稍後將添加默認的 HandlerMapping
			}
		}

		// 如果找不到其他映射,請通過註冊默認的 HandlerMapping 確保至少有一個 HandlerMapping
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName()
						+ "': using default");
			}
		}
	}

經過以上讀取過程,handlerMappings變量 就已經獲取了在 Bean 中配置好的映射關係。其他的初始化過程和 handlerMappings 比較類似,都是直接從 IoC容器 中讀入配置,所以這裏的 MVC初始化過程 是建立在 IoC容器 已經初始化完成的基礎上的。

4 SpringMVC處理分發HTTP請求

4.1 HandlerMapping的配置和設計原理

前面分析了 DispatcherServlet 對 SpringMVC框架 的初始化過程,在此基礎上,我們再進一步分析 HandlerMapping 的實現原理,看看這個 MVC框架 中比較關鍵的控制部分是如何實現的。

在初始化完成時,在上下文環境中已定義的所有 HandlerMapping 都已經被加載了,這些加載的 handlerMappings 被放在一個 List 中並被排序,存儲着 HTTP請求 對應的映射數據。這個 List 中的每一個元素都對應着一個具體 handlerMapping 的配置,一般每一個 handlerMapping 可以持有一系列從 URL請求 到 Controller 的映射,而 SpringMVC 提供了一系列的 HandlerMapping 實現。
在這裏插入圖片描述
以 SimpleUrlHandlerMapping 爲例來分析 HandlerMapping 的設計與實現。在 SimpleUrlHandlerMapping 中,定義了一個 Map 來持有一系列的映射關係。通過這些在 HandlerMapping 中定義的映射關係,即這些 URL請求 和控制器的對應關係,使 SpringMVC
應用 可以根據 HTTP請求 確定一個對應的 Controller。具體來說,這些映射關係是通過 HandlerMapping接口 來封裝的,在 HandlerMapping接口 中定義了一個 getHandler()方法,通過這個方法,可以獲得與 HTTP請求 對應的 HandlerExecutionChain,在這個 HandlerExecutionChain 中,封裝了具體的 Controller對象。

public interface HandlerMapping {

	String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

	String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";

	String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";

	String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";

	String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";

	String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";

	/**
	 * 返回的這個 HandlerExecutionChain 不但持有 handler本身,還包括了處理這個 HTTP請求 的攔截器鏈
	 */
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

這個 HandlerExecutionChain 的實現看起來比較簡潔,它持有一個 攔截器鏈(HandlerInterceptor對象列表) 和一個 handler對象,這個 handler對象 實際上就是 HTTP請求 對應的 Controller,在持有這個 handler對象 的同時,還在 HandlerExecutionChain 中設置了一個攔截器鏈,通過這個攔截器鏈中的攔截器,可以爲 handler對象 提供功能的增強。要完成這些工作,需要對攔截器鏈和 handler 都進行配置,這些配置都是在 HandlerExecutionChain 的初始化函數中完成的。爲了維護這個攔截器鏈和 handler,HandlerExecutionChain 還提供了一系列與攔截器鏈維護相關的操作,比如,爲攔截器鏈增加攔截器的 addInterceptor()方法。

public class HandlerExecutionChain {

	private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

	private final Object handler;

	private HandlerInterceptor[] interceptors;

	private List<HandlerInterceptor> interceptorList;

	private int interceptorIndex = -1;


	public HandlerExecutionChain(Object handler) {
		this(handler, null);
	}

	public HandlerExecutionChain(Object handler, HandlerInterceptor[] interceptors) {
		if (handler instanceof HandlerExecutionChain) {
			HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
			this.handler = originalChain.getHandler();
			this.interceptorList = new ArrayList<HandlerInterceptor>();
			CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
			CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
		}
		else {
			this.handler = handler;
			this.interceptors = interceptors;
		}
	}

	public Object getHandler() {
		return this.handler;
	}

	/**
	 * 爲攔截器鏈 添加攔截器
	 */
	public void addInterceptor(HandlerInterceptor interceptor) {
		initInterceptorList();
		this.interceptorList.add(interceptor);
	}

	/**
	 * 批量添加攔截器
	 */
	public void addInterceptors(HandlerInterceptor[] interceptors) {
		if (interceptors != null) {
			initInterceptorList();
			this.interceptorList.addAll(Arrays.asList(interceptors));
		}
	}

	/**
	 * 延遲初始化 interceptorList 和 interceptors集合
	 */
	private void initInterceptorList() {
		if (this.interceptorList == null) {
			this.interceptorList = new ArrayList<HandlerInterceptor>();
		}
		if (this.interceptors != null) {
			this.interceptorList.addAll(Arrays.asList(this.interceptors));
			this.interceptors = null;
		}
	}

	public HandlerInterceptor[] getInterceptors() {
		if (this.interceptors == null && this.interceptorList != null) {
			this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
		}
		return this.interceptors;
	}
	
	@Override
	public String toString() {
		if (this.handler == null) {
			return "HandlerExecutionChain with no handler";
		}
		StringBuilder sb = new StringBuilder();
		sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]");
		if (!CollectionUtils.isEmpty(this.interceptorList)) {
			sb.append(" and ").append(this.interceptorList.size()).append(" interceptor");
			if (this.interceptorList.size() > 1) {
				sb.append("s");
			}
		}
		return sb.toString();
	}
}

HandlerExecutionChain 中定義的 Handler 和 HandlerInterceptor[]屬性 需要在定義 HandlerMapping 時配置好,例如對具體的 SimpleURLHandlerMapping,要做的就是根據 URL映射 的方式,註冊 Handler 和 HandlerInterceptor[],從而維護一個反映這種映射關係的 handlerMap。當需要匹配 HTTP請求 時,需要查詢這個 handlerMap 中的信息來得到對應的 HandlerExecutionChain。這些信息是什麼時候配置好的呢?這裏有一個註冊過程,這個註冊過程在容器對 Bean 進行依賴注入時發生,它實際上是通過一個 Bean 的 postProcessor() 來完成的。以 SimpleHandlerMapping 爲例,需要注意的是,這裏用到了對容器的回調,只有 SimpleHandlerMapping 是 ApplicationContextAware 的子類才能啓動這個註冊過程。這個註冊過程完成的是反映 URL 和 Controller 之間映射關係的 handlerMap 的建立。
在這裏插入圖片描述

public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {

	@Override
	public void initApplicationContext() throws BeansException {
		super.initApplicationContext();
		registerHandlers(this.urlMap);
	}

	/**
	 * 爲相應的路徑註冊 URL映射 中指定的所有 handlers處理程序
	 */
	protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
		if (urlMap.isEmpty()) {
			logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
		}
		else {
			// 這裏對 bean 的配置進行解析,然後調用父類的 registerHandler()方法 進行解析
			for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
				String url = entry.getKey();
				Object handler = entry.getValue();
				// 如果 url 沒有斜線,就在前面加上斜線
				if (!url.startsWith("/")) {
					url = "/" + url;
				}
				// Remove whitespace from handler bean name.
				if (handler instanceof String) {
					handler = ((String) handler).trim();
				}
				// 這裏調用的是父類的方法
				registerHandler(url, handler);
			}
		}
	}
}

這個 SimpleUrlHandlerMapping 註冊過程的完成,很大一部分需要它的基類來配合,這個基類就是 AbstractUrlHandlerMapping。在 AbstractUrlHandlerMapping 的處理過程中,如果使用 Bean 的名稱作爲映射,那麼直接從容器中獲取這個 HTTP映射 對應的 Bean,然後還要對不同的 URL配置 進行解析處理,比如在 HTTP請求 中配置成 “/” 和 通配符“/*” 的 URL,以及正常的 URL請求,完成這個解析處理過程以後,會把 URL 和 handler 作爲鍵值對放到一個 handlerMap 中去。

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {

	/**
	 * 爲給定的 URL路徑 註冊指定的 handler處理程序
	 */
	protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
		Assert.notNull(urlPaths, "URL path array must not be null");
		for (String urlPath : urlPaths) {
			registerHandler(urlPath, beanName);
		}
	}

	/**
	 * 爲給定的 URL路徑 註冊指定的 handler處理程序
	 */
	protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
		Assert.notNull(urlPath, "URL path must not be null");
		Assert.notNull(handler, "Handler object must not be null");
		Object resolvedHandler = handler;

		// 如果使用 bean名稱 進行映射,就直接從 IoC容器 中獲取該 bean名稱 對應的 handler
		if (!this.lazyInitHandlers && handler instanceof String) {
			String handlerName = (String) handler;
			if (getApplicationContext().isSingleton(handlerName)) {
				resolvedHandler = getApplicationContext().getBean(handlerName);
			}
		}

		Object mappedHandler = this.handlerMap.get(urlPath);
		if (mappedHandler != null) {
			if (mappedHandler != resolvedHandler) {
				throw new IllegalStateException(
						"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
						"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
			}
		}
		else {
			// 處理 URL 是 "/" 的映射,把這個 "/" 映射的 controller 設置到 rootHandler 中
			if (urlPath.equals("/")) {
				if (logger.isInfoEnabled()) {
					logger.info("Root mapping to " + getHandlerDescription(handler));
				}
				setRootHandler(resolvedHandler);
			}
			// 處理 URL 是 "/" 的映射,把這個 "/" 映射的 controller 設置到 defaultHandler 中
			else if (urlPath.equals("/*")) {
				if (logger.isInfoEnabled()) {
					logger.info("Default mapping to " + getHandlerDescription(handler));
				}
				setDefaultHandler(resolvedHandler);
			}
			// 處理正常的 URL映射,此 handlerMap 的 key 和 value 分別代表 URL 和 映射的Controller
			else {
				this.handlerMap.put(urlPath, resolvedHandler);
				if (logger.isInfoEnabled()) {
					logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
				}
			}
		}
	}

	/**
	 * 爲此 handler映射 設置 根handler,即要爲根路徑("/")註冊的 handler
	 * <p>Default is {@code null}, indicating no root handler.
	 */
	public void setRootHandler(Object rootHandler) {
		this.rootHandler = rootHandler;
	}

	public Object getRootHandler() {
		return this.rootHandler;
	}

	/**
	 * 設置 此handler映射 的默認 handler。如果未找到特定映射,則將返回 此handler
	 */
	public void setDefaultHandler(Object defaultHandler) {
		this.defaultHandler = defaultHandler;
	}

	public Object getDefaultHandler() {
		return this.defaultHandler;
	}
}

這裏的 handlerMap 是一個 HashMap,其中保存了 “URL請求” --> “Controller對象” 的映射關係,這個 handlerMap 是在 AbstractUrlHandlerMapping 中定義的( Map<String, object> handlerMap = new LinkedHashMap<String, object>() ),這個配置好 URL請求 和 handler映射數據 的 handlerMap,爲 SpringMVC 響應 HTTP請求 準備好了基本的映射數據,根據這個 handlerMap 以及設置於其中的映射數據,可以方便地由 URL請求 得到它所對應的 handler。有了這些準備工作,SpringMVC 就可以等待 HTTP請求 的到來了。

4.2 使用HandlerMapping完成請求的映射處理

繼續通過 SimpleUrlHandlerMapping的實現 來分析 HandlerMapping 的 接口方法getHandler(),該方法會根據初始化時得到的映射關係來生成 DispatcherServlet 需要的 HandlerExecutionChain,也就是說,這個 getHandler()方法 是實際使用 HandlerMapping 完成請求的映射處理的地方。在前面的 HandlerExecutionChain 的執行過程中,首先在 AbstractHandlerMapping 中啓動 getHandler() 的調用。

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
	/**
	 * 查找給定請求的 handler,如果找不到特定的 handler,則返回到 defaultHandler
	 */
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		// 這裏用到了模板方法模式,getHandler() 是一個模板方法,定義了流程,getHandlerInternal() 則是
		// 一個抽象方法,交由子類實現
		Object handler = getHandlerInternal(request);
		// 如果找不到特定的 handler,則取 defaultHandler
		if (handler == null) {
			handler = getDefaultHandler();
		}
		// defaultHandler 也沒有則返回 null
		if (handler == null) {
			return null;
		}
		// 如果該 handler 是 String類型的,說明它是一個 beanName
		// 根據該 beanName 從 IoC容器 中獲取真正的 handler對象
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = getApplicationContext().getBean(handlerName);
		}
		// 這裏把 handler 添加到到 HandlerExecutionChain 中
		return getHandlerExecutionChain(handler, request);
	}
}

取得 handler 的具體過程在 getHandlerInternal()方法 中實現,這個方法接受 HTTP請求 作爲參數,它的實現在 AbstractHandlerMapping 的子類 AbstractUrlHandlerMapping 中,這個實現過程包括從 HTTP請求 中得到 URL,並根據 URL 到 urlMapping 中獲得 handler。

public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
	/**
	 * 查找 給定請求的URL 對應的 handler
	 */
	@Override
	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		// 從 request 中獲取請求的 URL路徑
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		// 將得到的 URL路徑 與 handler 進行匹配,得到對應的 handler,如果沒有對應的 handler
		// 則返回 null,這樣 默認的handler 會被使用
		Object handler = lookupHandler(lookupPath, request);
		if (handler == null) {
			// We need to care for the default handler directly, since we need to
			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			// 使用 默認的handler
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = getApplicationContext().getBean(handlerName);
				}
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
			}
		}
		if (handler != null && logger.isDebugEnabled()) {
			logger.debug("Mapping [" + lookupPath + "] to " + handler);
		}
		else if (handler == null && logger.isTraceEnabled()) {
			logger.trace("No handler mapping found for [" + lookupPath + "]");
		}
		return handler;
	}

	/**
	 * 查找給定 URL路徑 的 handler實例
	 */
	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// 直接匹配
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}
		// 正則匹配
		List<String> matchingPatterns = new ArrayList<String>();
		for (String registeredPattern : this.handlerMap.keySet()) {
			if (getPathMatcher().match(registeredPattern, urlPath)) {
				matchingPatterns.add(registeredPattern);
			}
		}
		String bestPatternMatch = null;
		Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
		if (!matchingPatterns.isEmpty()) {
			Collections.sort(matchingPatterns, patternComparator);
			if (logger.isDebugEnabled()) {
				logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
			}
			bestPatternMatch = matchingPatterns.get(0);
		}
		if (bestPatternMatch != null) {
			handler = this.handlerMap.get(bestPatternMatch);
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);

			// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
			// for all of them
			Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
			for (String matchingPattern : matchingPatterns) {
				if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
					Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
					Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
					uriTemplateVariables.putAll(decodedVars);
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
			}
			return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
		}
		// No handler found...
		return null;
	}
}

經過這一系列對 HTTP請求 進行解析和匹配 handler 的過程,得到了與請求對應的 handler處理器。在返回的 handler 中,已經完成了在 HandlerExecutionChain 中進行封裝的工作,爲 handler 對 HTTP請求 的響應做好了準備。

4.3 DispatcherServlet對HTTP請求的分發處理

DispatcherServlet 是 SpringMVC框架 中非常重要的一個類,不但建立了自己持有的 IoC容器,還肩負着請求分發處理的重任,對 HTTP請求 的處理是在 doService()方法 中完成的。DispatcherServlet 是 HttpServlet 的子類 ,與其他 HttpServlet 一樣,可以通過 doService() 來響應 HTTP的請求。然而,依照 SpringMVC 的使用,業務邏輯的調用入口是在 handler 的 handler()方法 中實現的,這是連接 SpringMVC 和應用業務邏輯實現的地方。

public class DispatcherServlet extends FrameworkServlet {

	/** 此 DispatcherServlet 使用的 HandlerMapping對象列表 */
	private List<HandlerMapping> handlerMappings;

	/** 此 DispatcherServlet 使用的 HandlerAdapter對象列表 */
	private List<HandlerAdapter> handlerAdapters;


	/**
	 * 公開 DispatcherServlet 特定的請求屬性,並將其委託給 doDispatch()方法 進行實際的分發
	 */
	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (logger.isDebugEnabled()) {
			// 得到 請求的URI
			String requestUri = urlPathHelper.getRequestUri(request);
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()
					? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'"
					+ resumed + " processing " + request.getMethod() + " request for ["
					+ requestUri + "]");
		}

		// Keep a snapshot of the request attributes in case of an include,
		// to be able to restore the original attributes after the include.
		Map<String, Object> attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			logger.debug("Taking snapshot of request attributes before include");
			attributesSnapshot = new HashMap<String, Object>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude
						|| attrName.startsWith("org.springframework.web.servlet")) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}

		// 使框架對象對處理程序和視圖對象可用
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE,
				getWebApplicationContext());
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

		FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request,
				response);
		if (inputFlashMap != null) {
			request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE,
					Collections.unmodifiableMap(inputFlashMap));
		}
		request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
		request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

		try {
			doDispatch(request, response);
		}
		finally {
			if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				return;
			}
			// Restore the original attribute snapshot, in case of an include.
			if (attributesSnapshot != null) {
				restoreAttributesAfterInclude(request, attributesSnapshot);
			}
		}
	}

	/** 
	 * 中央控制器,控制請求的轉發
	 * 對請求的處理實際上是由 doDispatch() 來完成的,它是 DispatcherServlet 完成 HTTP請求 分發處理的主要方法,
	 * 包括準備 ModelAndView,調用 getHandler()方法 來響應 HTTP請求,然後通過執行 Handler的處理 來獲取請求的
	 * 處理結果,最後把結果返回出去
	 */
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			// 爲視圖準備好一個 ModelAndView,這個 ModelAndView 持有 handler處理請求的結果
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				// 1.檢查是否是文件上傳的請求
				processedRequest = checkMultipart(request);
				multipartRequestParsed = processedRequest != request;

				// 2.取得處理當前請求的 Controller對象,這裏也稱爲 hanlder處理器,這裏並不是
				// 直接返回 controller對象,而是返回的 HandlerExecutionChain請求處理器鏈對象,
				// 該對象封裝了 handler 和 interceptors
				mappedHandler = getHandler(processedRequest, false);
				// 如果 handler 爲空,則返回 404
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 3. 獲取處理 request 的處理器適配器 HandlerAdapter 
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// 獲取 請求方式,如:GET, POST, PUT
				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;
					}
				}

				// 4.攔截器的預處理方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				try {
					// 5.實際的處理器處理請求,返回結果視圖對象
					mv = ha.handle(processedRequest, response,
							mappedHandler.getHandler());
				}
				finally {
					if (asyncManager.isConcurrentHandlingStarted()) {
						return;
					}
				}

				// 結果視圖對象的處理
				applyDefaultViewName(request, mv);
				// 6.攔截器的後處理方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv,
					dispatchException);
		}
		catch (Exception ex) {
			// 請求成功響應之後的方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler,
					err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest,
						response);
				return;
			}
			// 清除多部分請求使用的所有資源
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}

	/**
	 * 返回此請求的 HandlerExecutionChain,按順序嘗試所有的 HandlerMapping
	 */
	@Deprecated
	protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache)
			throws Exception {
		return getHandler(request);
	}
	
	/**
	 * 返回此請求的 HandlerExecutionChain
	 */
	protected HandlerExecutionChain getHandler(HttpServletRequest request)
			throws Exception {
		// 遍歷 此servlet 使用的 HandlerMapping列表
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler map [" + hm
						+ "] in DispatcherServlet with name '" + getServletName() + "'");
			}
			// 查找給定請求的 handler
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}
	
	/**
	 * 返回 此處理程序對象handler 的 HandlerAdapter
	 */
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		// 對所有持有的 HandlerAdapter 進行匹配
		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
				+ "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}
}

通過判斷,可以知道這個 handler 是不是 Controller接口 的實現,比如可以通過具體 HandlerAdapter 的實現來了解這個適配過程。以 SimpleControllerHandlerAdapter的實現 爲例來了解這個判斷是怎樣起作用的。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	// 判斷要執行的 handler 是不是 Controller類型的
	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;
	}

}

經過上面一系列的處理,得到了 handler對象,接着就可以開始調用 handler對象 中的 HTTP響應動作了。在 handler 中封裝了應用業務邏輯,由這些邏輯對 HTTP請求 進行相應的處理,生成需要的數據,並把這些數據封裝到 ModelAndView對象 中去,這個 ModelAndView 的數據封裝是 SpringMVC框架 的要求。對 handler 來說, 這些都是通過調用 handler()方法 中的 handleRequest()方法 來觸發完成的。在得到 ModelAndView對象 以後,這個 ModelAndView對象 會被交給 MVC模式 中的視圖類,由視圖類對 ModelAndView對象 中的數據進行呈現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章