【SpringMVC源码三千问】DispatcherServlet源码解析

时间:2023-02-11 22:01:52

DispatcherServlet#doDispatch() 是 SpringMVC 处理请求分发的方法,只要是 spring mvc 处理的 http 请求,都会经过 DispatcherServlet 的请求分发处理,从而调用相应的 handler method。

DispatcherServlet#doDispatch() 源码分析:

【SpringMVC源码三千问】DispatcherServlet源码解析

可以看到,DispatcherServlet#doDispatch() 的处理大体分了 6 步:
1、获取 request 对应的 HandlerExecutionChain(它包含 handler 和 interceptors)
2、获取 handler 对应的 HandlerAdapter
3、执行 handler 的前置处理: HandlerInterceptor#preHandle()
4、通过 HandlerAdapter#handler() 来执行处理程序
5、执行 handler 的后置处理:HandlerInterceptor#postHandle()
6、对返回值进行处理(包括正常返回 和 异常处理)

处理程序 handler 始终包装在 HandlerExecutionChain 实例中,HandlerExecutionChain 中可以附带一些 HandlerInterceptor
DispatcherServlet 将首先按给定顺序调用每个 HandlerInterceptor#preHandle() 方法,如果所有 preHandle 都返回 true 的话,才会调用处理程序 handler 本身。

所以,如果我们想要找 url 与 handler method 的映射关系的话,就可以从 DispatcherServlet#getHandler() 来入手,打个断点调试。

HandlerExecutionChain 的获取 和 组装

HandlerExecutionChain 是 handler 的执行链,它是由 handler 和 interceptors 组成的。

HandlerExecutionChain 是通过 DispatcherServlet#getHandler() 来获取的:

/**
 * 将所有的 HandlerMapping 按顺序遍历一次,获取 request 对应的 HandlerExecutionChain。
 */
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

可以看到,在获取 HandlerExecutionChain 时,Spring 会将所有的 HandlerMapping 按顺序遍历一次。
而在 Spring 中有许多 HandlerMapping,最常用的当属 RequestMappingHandlerMapping

HandlerExecutionChain 的获取

HandlerExecutionChain 的获取是在 AbstractHandlerMapping#getHandler() 中完成的。
主要分成了两步:
1、获取 request 对应的 handler 程序
2、将 handler 和 相应的 HandlerInterceptors 组装成 HandlerExecutionChain

【SpringMVC源码三千问】DispatcherServlet源码解析

AbstractHandlerMapping#getHandler() 中包含了对 cors 的处理,具体是往 HandlerExecutionChain 中添加了 CorsInterceptor。
@see AbstractHandlerMapping#getCorsHandlerExecutionChain()

HandlerExecutionChain 的构造和组装过程

HandlerExecutionChain 的构造组装是在 AbstractHandlerMapping#getHandlerExecutionChain()

/**
 * 为给定的 handler 构建 HandlerExecutionChain(包含 handler 和 HandlerInterceptor)。
 */
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    // 1、根据 handler 构造 HandlerExecutionChain  
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    // 2、给 HandlerExecutionChain 添加 HandlerInterceptor  
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(request)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        } else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

DispatcherServlet 中使用的默认策略接口

DispatcherServlet.properties 中指定了 DispatcherServlet.java 中使用的一些策略接口的默认实现:

# spring-webmvc-5.3.9.jar!/org/springframework/web/servlet/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.function.support.RouterFunctionMapping

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.function.support.HandlerFunctionAdapter


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

小结

DispatcherServlet#doDispatch() 是 Spring MVC 处理请求分发的方法,它的处理大体分了 6 步:
1、获取 request 对应的 HandlerExecutionChain(它包含 handler 和 interceptors)
2、获取 handler 对应的 HandlerAdapter
3、执行 handler 的前置处理: HandlerInterceptor#preHandle()
4、通过 HandlerAdapter#handler() 来执行处理程序
5、执行 handler 的后置处理:HandlerInterceptor#postHandle()
6、对返回值进行处理(包括正常返回 和 异常处理)

HandlerExecutionChain 是 handler 的执行链,它是由 handler 和 interceptors 组成的。
HandlerExecutionChain 是由 HandlerMapping#getHandler() 返回的。