SpringMvc源码分析4.1——HandlerAdapter


一. 准备

接着上一篇,我们暴露的接口:

@RestController
public class IndexController {
    @GetMapping("/hello")
    public String hello(String name) {
        return "hello: " + name;
    }
}

bebug到DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 1. 关注点一
				mappedHandler = getHandler(processedRequest);
				
				// 2. todo待分析,关注点二
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			  // 3. todo待分析,关注点三
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  
  			// 4. todo待分析,关注点四
				applyDefaultViewName(processedRequest, mv);
			
  			// 5. todo待分析,关注点五
 			  processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	
	}

二. 分析

1. 关注几个属性值

我们先看一下DispatcherServlet内部几个属性此时的值:

/** List of HandlerMappings used by this servlet. */
	@Nullable
	private List<HandlerMapping> handlerMappings;

	/** List of HandlerAdapters used by this servlet. */
	@Nullable
	private List<HandlerAdapter> handlerAdapters;

	/** List of HandlerExceptionResolvers used by this servlet. */
	@Nullable
	private List<HandlerExceptionResolver> handlerExceptionResolvers;

	/** RequestToViewNameTranslator used by this servlet. */
	@Nullable
	private RequestToViewNameTranslator viewNameTranslator;
	
/** List of ViewResolvers used by this servlet. */
	@Nullable
	private List<ViewResolver> viewResolvers;
  • handlerMappings handlerMappings

  • handlerAdapters

  • handlerExceptionResolvers handlerExceptionResolvers

  • viewNameTranslatorviewNameTranslator

  • viewResolversviewResolvers

2. 关注点二源码

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

这里主要是根据获取到的handler找到匹配的HandlerAdapter,源码如下:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

首先我们再次看一下HandlerAdapter结构图

HandlerAdapter

public interface HandlerAdapter {
	// 判断是否支持给定的handler
	boolean supports(Object handler);

  // 用给定的handler处理请求
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	long getLastModified(HttpServletRequest request, Object handler);

}

比如,我们测试的项目,注入的HandlerAdapter为:

handlerAdapters

HandlerAdapter类型 支持的handler
HttpRequestHandlerAdapter HttpRequestHandler
SimpleControllerHandlerAdapter org.springframework.web.servlet.mvc.Controller实例
RequestMappingHandlerAdapter handler instanceof HandlerMethod

SpringMvc源码分析3——HandlerMapping可以知道,handler类型为HandlerMethod,所以,这一步getHandlerAdapter得到的HandlerAdapterRequestMappingHandlerAdapter

关注点二就分析到这,那么大家有没有疑问,DispatcherServlet里面的这些属性,如handlerAdapters是什么时候初始化的呢?

三. handlerAdapters等的初始化

既然DispatcherServletServlet,那么就肯定会执行它的init()方法;

观察DispatcherServlet,发现里面有一个DispatcherServlet#initStrategies方法,如下:

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

这里面包含了一系列属性的初始化。那么直接在这个方法内debug,然后启动springboot应用,可以看到调用栈:

initStrategies

我们可以看到Servletinit()调用过程。

然后来看下, initHandlerAdapters(context)源码:

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

   //  detectAllHandlerAdapters 默认为true
   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<>(matchingBeans.values());
         // We keep HandlerAdapters in sorted order.
         AnnotationAwareOrderComparator.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.isTraceEnabled()) {
         logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
               "': using default strategies from DispatcherServlet.properties");
      }
   }
}

初始化handlerAdapters分了这几种情况:

  1. detectAllHandlerAdaptertrue(默认就为true),会从应用上下文中找到所有的HandlerAdapters,然后做一个排序。

  2. detectAllHandlerAdapterfalse,就会找到名称为handlerAdapterhandlerAdapter

  3. 最后,如果handlerAdapters仍然为空,则会走默认的策略。这默认的实现可以在DispatcherServlet.properties查看到,如下:

    # Default implementation classes for DispatcherServlet's strategy interfaces.
    # Used as fallback when no matching beans are found in the DispatcherServlet context.
    # Not meant to be customized by application developers.
    
    org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
    
    org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
    
    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
    
    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
    	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
    
    org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
    	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
    	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
    
    org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
    
    org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
    
    org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

文章作者: shiv
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 shiv !
评论
  目录