SpringMVC中的HandlerAdapter

来源:互联网 发布:开源软件二次开发 编辑:程序博客网 时间:2024/06/06 02:02

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