一. 准备
接着上一篇,我们暴露的接口:
@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
handlerAdapters
handlerExceptionResolvers
viewNameTranslator
viewResolvers
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结构图
:
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
为:
HandlerAdapter类型 | 支持的handler |
---|---|
HttpRequestHandlerAdapter | HttpRequestHandler |
SimpleControllerHandlerAdapter | org.springframework.web.servlet.mvc.Controller实例 |
RequestMappingHandlerAdapter | handler instanceof HandlerMethod |
从SpringMvc源码分析3——HandlerMapping可以知道,handler
类型为HandlerMethod
,所以,这一步getHandlerAdapter
得到的HandlerAdapter
为RequestMappingHandlerAdapter
。
关注点二就分析到这,那么大家有没有疑问,DispatcherServlet
里面的这些属性,如handlerAdapters
是什么时候初始化的呢?
三. handlerAdapters等的初始化
既然
DispatcherServlet
是Servlet
,那么就肯定会执行它的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
应用,可以看到调用栈:
我们可以看到Servlet
的init()
调用过程。
然后来看下, 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
分了这几种情况:
detectAllHandlerAdapter
为true
(默认就为true
),会从应用上下文中找到所有的HandlerAdapters
,然后做一个排序。detectAllHandlerAdapter
为false
,就会找到名称为handlerAdapter
的handlerAdapter
。最后,如果
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