SpringMVC中的HandlerAdapter

SpringMVC中的HandlerAdapter


  還記得在DispatcherServlet中SpringMVC處理請求的邏輯嗎,網上有一個非常棒的圖,闡明瞭請求分發處理的整個過程。


 

   映射處理器HandlerMapping根據Request返回一個HandlerExecutionChain實例,HandlerExecutionChain並不是真正的處理器Handler,而是包含了Handler以及攔截器HandlerInterceptor的封裝後的調用鏈對象。系統中可能存在多個HandlerMapping,不同的HandlerMapping對應着不同的策略。DispatcherServlet根據先後順序,哪個HandlerMapping最先找到處理器,則使用當前的處理器並且立即停止繼續查找。

  

    DispatcherServlet獲取到處理器Handler後,它並不知道如何使用這個處理器。因爲處理器可能多種多樣,沒有遵循一種標準,它只是一個Object。所以這裏需要多Handler進行適配,使得所有的處理器共同擁有一個標準的接口處理請求。Spring使用的適配器的名字就是HandlerAdapter,看它的定義:

public interface HandlerAdapter {	

	boolean supports(Object handler); 
	
	
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	
	long getLastModified(HttpServletRequest request, Object handler);

}
  supports方法用來判斷是否支持當前的處理器,handler方法用來處理請求返回ModelAndView。選取HandlerAdapter的方式跟HandlerMapping的方式非常相似,只不過一個是根據請求選取處理器,一個是根據處理器選取處理器的適配器。下面是選取HandlerAdapter的方法

	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需要與HandlerMapping配合使用,如果HandlerMapping返回的處理器沒有對應的適配器是會出現異常的。

HandlerAdapter的初始化

  和HandlerMapping一樣,HandlerAdapter的初始化也在DispatcherServlet的initStrategies方法中,具體初始化方法如下:

	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");
			}
		}
	}
  首先嚐試向容器索取HandlerAdapter,索要的方式分爲兩種:第一種是根據類型獲取所有的HandlerAdapter類型的Bean,另一種是根據名字向容器索要名字爲“handlerAdapter”的Bean。具體使用哪種方式根據參數detectAllHandlerAdapters決定,默認爲true,可以在web.xml中設置。


   若容器中沒有找到HandlerAdapter,則spring會加載使用默認的HandlerAdapter。其實不僅HandlerAdapter是這樣,DispatcherServlet的一些其它組件在某些情況也會使用默認的配置。它們通過一個共同的方法獲取:

	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<T>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]", ex);
				}
				catch (LinkageError err) {
					throw new BeanInitializationException(
							"Error loading DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]: problem with class file or dependent class", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<T>();
		}
	}
 

這個defaultStrategies加載自配置文件,加載過程如下

	private static final Properties defaultStrategies;

	static {
		// Load default strategy implementations from properties file.
		// This is currently strictly internal and not meant to be customized
		// by application developers.
		try {
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
		}
	}
 

找到對應位置的配置文件,並且找到關於HandlerAdapter的配置

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
 

如上所示,容器中HandlerAdapter的時候就會使用配置好的上面的三種HandlerAdapter。如果在spring的配置文件中加 <mvc:annotation-driven />,則它的實現類AnnotationDrivenBeanDefinitionParser會自動向容器註冊RequestMappingHandlerAdapter和RequestMappingHandlerMapping。

發佈了51 篇原創文章 · 獲贊 11 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章