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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值