springmvc 核心流程源码分析

微信扫一扫,分享到朋友圈

springmvc 核心流程源码分析

0. 目录

0. 目录
1. DispatcherServlet 类的启动
1.1 SpringServletContainerInitializer 初始化器
1.2 WebApplicationInitializer web 应用初始化器
1.3 AbstractDispatcherServletInitializer
2. DispatcherServlet 的初始化
2.1 HttpServletBean init() 初始化方法
2.2 FrameworkServlet initServletBean() 初始化 ServletBean
2.3 DispatcherServlet onRefresh() 初始化
2.3.1 initMultipartResolver() 初始化多部分解析器
2.3.2 initLocaleResolver() 初始化本地解析器
2.3.2.1 getDefaultStrategy() 获取默认策略
2.3.2.2 AcceptHeaderLocaleResolver 接收请求头本地解析器
2.3.3 initThemeResolver() 初始化主题解析器
2.3.4 initHandlerMappings() 初始化映射处理器
2.3.4.1 HandlerMapping 映射处理器
2.3.4.2 AbstractHandlerMapping 的 getHandler() 方法
2.3.4.3 AbstractUrlHandlerMapping 类的 getHandlerInternal() 方法
2.3.4.4 AbstractUrlHandlerMapping 的 registerHandler() 注册处理器方法
2.3.4.5 AbstractDetectingUrlHandlerMapping 的 detectHandlers() 发现处理器
2.3.4.6 BeanNameUrlHandlerMapping 的 determineUrlsForHandler()
2.3.4.8 AbstractHandlerMapping 的 initApplicationContext() 初始化容器方法
2.3.4.9 AbstractHandlerMethodMapping 的 getHandlerInternal() 方法
2.3.4.10 RequestMappingHandlerMapping 请求映射处理器映射
2.3.5 initHandlerAdapters() 初始化处理器适配器
2.3.5.1 HandlerAdapter 处理器适配器
2.3.5.2 HttpRequestHandlerAdapter
2.3.5.3 SimpleControllerHandlerAdapter
2.3.5.4 RequestMappingHandlerAdapter(重点)
2.3.6 initHandlerExceptionResolvers() 初始化处理器异常解析器
2.3.6.1 HandlerExceptionResolver 处理器异常解析器
2.3.7 initRequestToViewNameTranslator() 初始化请求试图名称转化器
2.3.8 initViewResolvers() 初始化视图解析器
2.3.8.1 ViewResolver 视图解析器
2.3.9 initFlashMapManager() 初始化刷新映射管理器
3. DispatchServlet 执行

Spring MVC 核心流程源码分析。

spring mvc 的核心流程主要体现在 DispatcherServlet 这个类上。

这个类的全类名是:org.springframework.web.servlet.DispatcherServlet,看下它的类图:

可以看到它间接实现了 JAVAX 的 servlet-api 中 Servlet 接口,Servlet 接口的主要方法如下:

可以看到 Servlet 接口提供了初始化 init()、服务 service()、销毁 destory() 方法,它的子类会实现这些接口。其中它的子类 FrameworkServlet 实现了主要的接口,留下一个 doService() 抽象方法,交给了 DispatcherServlet 类去实现。

所以我们就会以下几个方便来分析 DispatcherServlet 的源码:

  1. DispatcherServlet 类的创建;
  2. DispatcherServlet 的初始化流程;
  3. DispatcherServlet 类的 doService() 方法调用逻辑

1. DispatcherServlet 类的启动

我们看下 DispatcherServlet 类是如何创建的,它有两个构造器方法:

public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
setDispatchOptionsRequest(true);
}
public DispatcherServlet() {
super();
setDispatchOptionsRequest(true);
}

通过 idea 的查询方法被使用功能(mac 快捷键是 control + alt + h),能知道它的调用栈:

DispatcherServlet.DispatcherServlet(WebApplicationContext)
AbstractDispatcherServletInitializer.createDispatcherServlet(WebApplicationContext)  (org.springframework.web.servlet.support)
AbstractDispatcherServletInitializer.registerDispatcherServlet(ServletContext)  (org.springframework.web.servlet.support)
AbstractDispatcherServletInitializer.onStartup(ServletContext)  (org.springframework.web.servlet.support)
SpringServletContainerInitializer.onStartup(Set<Class<?>>, ServletContext)  (org.springframework.web)
StandardContext.startInternal()  (org.apache.catalina.core)
...省略 Tomcat 内部...
匿名在deploy() 在 DeploymentManagerImpl.call(HttpServerExchange, Object)  (io.undertow.servlet.core)
ServletContainerInitializerServletContextListener在ContainerInitializer.contextInitialized(ServletContextEvent)  (org.eclipse.jetty.servlet.listener)
...省略 jetty 内部...

可以看到,这个 DispatcherServlet 有参构造器最根本调用是在三个 web 服务器启动时调用的,至于它们是怎么样启动,我们以后会开专题分析它们服务器的源码启动流程,这里就先大概知道,就是在 web 容器启动的时候会创建。然后 web 容器会调用了 SpringServletContainerInitializer 类的 onStartup() 方法来启动。

1.1 SpringServletContainerInitializer 初始化器

它的类图:

看下它的实现 org.springframework.web.SpringServletContainerInitializer:

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
/**
* Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
* implementations present on the application classpath.
* <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
* Servlet 3.0+ containers will automatically scan the classpath for implementations
* of Spring's {@code WebApplicationInitializer} interface and provide the set of all
* such types to the {@code webAppInitializerClasses} parameter of this method.
* <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,
* this method is effectively a no-op. An INFO-level log message will be issued notifying
* the user that the {@code ServletContainerInitializer} has indeed been invoked but that
* no {@code WebApplicationInitializer} implementations were found.
* <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,
* they will be instantiated (and <em>sorted</em> if the @{@link
* org.springframework.core.annotation.Order @Order} annotation is present or
* the {@link org.springframework.core.Ordered Ordered} interface has been
* implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}
* method will be invoked on each instance, delegating the {@code ServletContext} such
* that each instance may register and configure servlets such as Spring's
* {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},
* or any other Servlet API componentry such as filters.
* @param webAppInitializerClasses all implementations of
* {@link WebApplicationInitializer} found on the application classpath
* @param servletContext the servlet context to be initialized
* @see WebApplicationInitializer#onStartup(ServletContext)
* @see AnnotationAwareOrderComparator
*/
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
// 初始化 web 应用初始化器
List<WebApplicationInitializer> initializers = Collections.emptyList();
if (webAppInitializerClasses != null) {
initializers = new ArrayList<>(webAppInitializerClasses.size());
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
// 实例化 WebApplicationInitializer 类型
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
// 启动 web 容器
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}

它是一个实现了 ServletContainerInitializer 接口的类,在 web 服务器启动的时候会调用这个类的 onStartup() 方法,同时 SpringServletContainerInitializer 类使用了 @HandlesTypes 注解,指定了 onStartup() 方法的入参参数类型。

它的 onStartup() 方法流程:

  1. 解析参数 webAppInitializerClasses 的类型(WebApplicationInitializer 类型)进行实例化,保存到集合中;
  2. 对集合进行排序;
  3. 遍历集合,执行 WebApplicationInitializer 的 onStartup() 方法。

1.2 WebApplicationInitializer web 应用初始化器

我们看下 WebApplicationInitializer 类的类图:

WebApplicationInitializer 接口只提供一个方法 org.springframework.web.WebApplicationInitializer#onStartup。

1.3 AbstractDispatcherServletInitializer

我们重点看下 org.springframework.web.servlet.support.AbstractDispatcherServletInitializer#onStartup 方法:

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 启动容器,创建 Root web 容器
super.onStartup(servletContext);
// 注册 DispatcherServlet,web 子容器
registerDispatcherServlet(servletContext);
}
protected void registerDispatcherServlet(ServletContext servletContext) {
// 获取 servlet 名称
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return null or empty");
// 创建一个 web 应用程序子容器
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");
// 创建一个 servlet
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
// 设置 servlet 容器初始化参数
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
// 把 servlet 添加到 Tomcat 容器中。
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
if (registration == null) {
throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
"Check if there is another servlet registered under the same name.");
}
// 设置启动
registration.setLoadOnStartup(1);
// 添加 servlet 映射
registration.addMapping(getServletMappings());
// 设置异步支撑
registration.setAsyncSupported(isAsyncSupported());
// 获取所有的过滤器
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
// 注册过滤器到 Tomcat 中
registerServletFilter(servletContext, filter);
}
}
// 自定义注册
customizeRegistration(registration);
}
/**
* 创建一个 DispatcherServlet
*
* Create a {@link DispatcherServlet} (or other kind of {@link FrameworkServlet}-derived
* dispatcher) with the specified {@link WebApplicationContext}.
* <p>Note: This allows for any {@link FrameworkServlet} subclass as of 4.2.3.
* Previously, it insisted on returning a {@link DispatcherServlet} or subclass thereof.
*/
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
// 创建一个 DispatcherServlet
return new DispatcherServlet(servletAppContext);
}

它的父类 onStartup() 方法是 org.springframework.web.context.AbstractContextLoaderInitializer#onStartup:

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 注册容器加载器监听器
registerContextLoaderListener(servletContext);
}
protected void registerContextLoaderListener(ServletContext servletContext) {
// 创建一个 Root 应用程序容器
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
// 容器加载监听器
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}

其中 createRootApplicationContext() 方法,有被子类 org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer#createRootApplicationContext 所实现:

@Override
@Nullable
protected WebApplicationContext createRootApplicationContext() {
// 获取 Root 配置类
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
// 创建注解配置 web 容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(configClasses);
return context;
}
else {
return null;
}
}

它提供创建 Servlet 应用程序上下文方法,org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer#createServletApplicationContext:

@Override
protected WebApplicationContext createServletApplicationContext() {
// 创建一个 AnnotationConfigWebApplicationContext 类型的 web 容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
// 获取 servlet 的配置类信息
Class<?>[] configClasses = getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
// 注册到容器中
context.register(configClasses);
}
return context;
}

梳理下 AbstractDispatcherServletInitializer 的 onStartup() 方法逻辑:

  1. 调用父类方法 onStartup();
    1. 创建一个 Root 应用程序容器 AnnotationConfigWebApplicationContext 类型;
    2. 为容器添加监听器 ContextLoaderListener。
  2. 调用 registerDispatcherServlet 注册一个 DispatcherServlet。
    1. 调用 createServletApplicationContext() 方法,创建一个 web 应用程序子容器 AnnotationConfigWebApplicationContext 类型;
    2. 调用 createDispatcherServlet() 方法,创建一个 DispatcherServlet 类;
    3. 为 dispatcherServlet 设置初始化参数;
    4. 把 dispatcherServlet 注册到参数 ServletContext 中。

以上就是 DispatcherServlet 类的创建流程了。总结为它是随着 web 服务容器(Tomcat、jetty 等)启动来启动的。

2. DispatcherServlet 的初始化

现在看下它的初始化方法,看看它的初始化到底做了什么事情的呢?我们通过上面分析 DispatcherServlet 是一个 Servlet,它有 init() 方法,那我们就看下它实现类是怎么实现 init() 方法的。

2.1 HttpServletBean init() 初始化方法

根据类图从 Servlet 往下一层层的看它的子类的 init() 方法实现,其中 HttpServletBean 类重写了 init() 方法,org.springframework.web.servlet.HttpServletBean#init:

@Override
public final void init() throws ServletException {
// 设置 bean 属性
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
// bean 包装器
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
// 资源加载器
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
// 初始化 bean 包装器
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// 初始化 servlet 容器
// Let subclasses do whatever initialization they like.
initServletBean();
}
protected void initServletBean() throws ServletException {
}

它提供了一个抽象的模板方法 initServletBean() 交给子类去实现了。

2.2 FrameworkServlet initServletBean() 初始化 ServletBean

其中它的子类 FrameworkServlet 实现了该方法, org.springframework.web.servlet.FrameworkServlet#initServletBean:

/**
* Tomcat 容器会调用 HttpServlet 的 init 方法,然后会调用到 initServletBean 初始化方法
*
* Overridden method of {@link HttpServletBean}, invoked after any bean properties
* have been set. Creates this servlet's WebApplicationContext.
*/
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("Initializing Servlet '" + getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
// 初始化 web 容器
this.webApplicationContext = initWebApplicationContext();
// 初始化框架 Servlet(空方法)
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
if (logger.isDebugEnabled()) {
String value = this.enableLoggingRequestDetails ?
"shown which may lead to unsafe logging of potentially sensitive data" :
"masked to prevent unsafe logging of potentially sensitive data";
logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
"': request parameters and headers will be " + value);
}
if (logger.isInfoEnabled()) {
logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
}
}

这里边 initWebApplicationContext() 方法最为重要,org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext:

/**
* 初始化和发布子容器
*
* Initialize and publish the WebApplicationContext for this servlet.
* <p>Delegates to {@link #createWebApplicationContext} for actual creation
* of the context. Can be overridden in subclasses.
* @return the WebApplicationContext instance
* @see #FrameworkServlet(WebApplicationContext)
* @see #setContextClass
* @see #setContextConfigLocation
*/
protected WebApplicationContext initWebApplicationContext() {
// 获取父容器
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
// 初始化 web 应用程序子容器
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
// 为子容器设置父容器
cwac.setParent(rootContext);
}
// 配置和刷新 web 应用容器
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// 创建一个 web 应用容器
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
// 刷新容器
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
/**
* 配置与刷新 web 容器
*
* @param wac
*/
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}
// s设置 servlet 信息
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
// 获取环境信息,初始化属性源
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
// 后置处理 web 容器(空方法)
postProcessWebApplicationContext(wac);
// 应用初始化
applyInitializers(wac);
// 执行刷新容器,即初始化容器
wac.refresh();
}
@Nullable
protected WebApplicationContext findWebApplicationContext() {
String attrName = getContextAttribute();
if (attrName == null) {
return null;
}
WebApplicationContext wac =
WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
}
return wac;
}
protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
return createWebApplicationContext((ApplicationContext) parent);
}
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
// 创建一个可配置的 web 应用容器
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
// 配置和刷新 web 子容器
configureAndRefreshWebApplicationContext(wac);
return wac;
}
protected void onRefresh(ApplicationContext context) {
// For subclasses: do nothing by default.
}

这里边 initWebApplicationContext() 的流程是:

  1. 获取 web 应用父容器 WebApplicationContext;
  2. 获取 web 应用子容器,如果不为null,则设置它的父容器属性,并且配置和刷新 web 子应用容器;
    1. 为 web 子容器设置 servletContext、ServletConfig、namespace、容器监听器信息;
    2. 获取容器的环境信息,为其初始化属性源配置;
    3. 后置处理 web 容器;
    4. 应用容器初始化;
    5. 执行刷新容器。
  3. 如果 web 子容器为空,则创建 web 子容器,并且配置和刷新 web 子容器;
  4. 刷新事件已经被接收,则执行 onRefresh(wac) 方法,刷新 web 子容器;
  5. 把 web 子容器作为属性发布到 ServletContext 中。
  6. 返回 web 子容器。

2.3 DispatcherServlet onRefresh() 初始化

上面逻辑中的第 4 步是 FrameworkServlet类提供了抽象的 onRefresh() 方法,留给了子类 DispatcherServlet 实现,org.springframework.web.servlet.DispatcherServlet#onRefresh:

/**
* This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
// 刷新应用程序
initStrategies(context);
}
/**
* 初始化策略
*
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
// 初始化多部分解析器
initMultipartResolver(context);
// 初始化本地解析器
initLocaleResolver(context);
// 初始化主题解析器
initThemeResolver(context);
// 初始化映射处理器
initHandlerMappings(context);
// 初始化处理器适配器
initHandlerAdapters(context);
// 初始化处理器异常解析器
initHandlerExceptionResolvers(context);
// 初始化请求试图名称转化器
initRequestToViewNameTranslator(context);
// 初始化视图解析器
initViewResolvers(context);
// 初始化刷新映射管理器你
initFlashMapManager(context);
}

这边我们挨个看下这些方法:

  1. initMultipartResolver() 初始化多部分解析器;
  2. initLocaleResolver() 初始化本地解析器;
  3. initThemeResolver() 初始化主题解析器;
  4. initHandlerMappings() 初始化映射处理器;
  5. initHandlerAdapters() 初始化处理器适配器;
  6. initHandlerExceptionResolvers() 初始化处理器异常解析器;
  7. initRequestToViewNameTranslator() 初始化请求试图名称转化器;
  8. initViewResolvers() 初始化视图解析器;
  9. initFlashMapManager() 初始化刷新映射管理器你

我们先介绍下这些组件,这是 springMVC 的核心组件,用于处理请求用的。

2.3.1 initMultipartResolver() 初始化多部分解析器

看下它的实现逻辑,org.springframework.web.servlet.DispatcherServlet#initMultipartResolver:

/**
* Initialize the MultipartResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* no multipart handling is provided.
*/
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.multipartResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isTraceEnabled()) {
logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
}
}
}

这里是通过容器获取 MultipartResolver 类型的实例。

2.3.2 initLocaleResolver() 初始化本地解析器

这个方法 org.springframework.web.servlet.DispatcherServlet#initLocaleResolver:

/**
* Initialize the LocaleResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to AcceptHeaderLocaleResolver.
*/
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.localeResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 从配置文件中获取默认的类型
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
}
}
}

这里的逻辑是:

  1. 从 spring bean 工厂中获取 LocaleResolver 类型的实例;
  2. 如果没有获取到,那就调用调用 getDefaultStrategy() 方法来根据默认的策略来获取;
  3. 如果返回的策略类有多个就会报错,只允许有一个结果。

2.3.2.1 getDefaultStrategy() 获取默认策略

我们看下这个默认的获取策略是如何实现的,org.springframework.web.servlet.DispatcherServlet#getDefaultStrategy:

private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
/**
* Return the default strategy object for the given strategy interface.
* <p>The default implementation delegates to {@link #getDefaultStrategies},
* expecting a single object in the list.
* @param context the current WebApplicationContext
* @param strategyInterface the strategy interface
* @return the corresponding strategy object
* @see #getDefaultStrategies
*/
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
List<T> strategies = getDefaultStrategies(context, strategyInterface);
if (strategies.size() != 1) {
throw new BeanInitializationException(
"DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
}
return strategies.get(0);
}
/**
* Create a List of default strategy objects for the given strategy interface.
* <p>The default implementation uses the "DispatcherServlet.properties" file (in the same
* package as the DispatcherServlet class) to determine the class names. It instantiates
* the strategy objects through the context's BeanFactory.
* @param context the current WebApplicationContext
* @param strategyInterface the strategy interface
* @return the List of corresponding strategy objects
*/
@SuppressWarnings("unchecked")
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
if (defaultStrategies == null) {
try {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
// 加载默认的 DispatcherServlet 配置文件,里边有一些默认的基础组件
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(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(
"Unresolvable class definition for DispatcherServlet's default strategy class [" +
className + "] for interface [" + key + "]", err);
}
}
return strategies;
}
else {
return Collections.emptyList();
}
}
/**
* Create a default strategy.
* <p>The default implementation uses
* {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean}.
* @param context the current WebApplicationContext
* @param clazz the strategy implementation class to instantiate
* @return the fully configured strategy instance
* @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory()
* @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean
*/
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}

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

看下这边的逻辑:

  1. 加载默认的 DispatcherServlet 配置文件 DispatcherServlet.properties,这里边有一些默认的基础组件信息,正是我们要讲解的初始化的组件;
  2. 保存加载好的配置文件中的属性信息;
  3. 根据方法参数传入的策略接口类型,从属性信息中查找对应的配置类;
  4. 如果配置类存在,则调用 createDefaultStrategy() 方法,让 spring 容器进行创建和管理配置类实例,最后返回配置类信息。

2.3.2.2 AcceptHeaderLocaleResolver 接收请求头本地解析器

从上面的 dispatchServelt.properties 文件中我们可以看到 org.springframework.web.servlet.LocaleResolver 配置类是 org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver。

看下它的类图:

这个类实现了 LocaleResolver 接口的两个方法,一个是 resolveLocale() 方法,是从当前请求中获取 Local 对象;另一个方法是 setLocale() 方法,设置 Local 对象。

至于它的使用,我们会在 DispatchServlet 的执行逻辑中会讲解到。

2.3.3 initThemeResolver() 初始化主题解析器

接着看,它是一个初始化主题解析器,主题是,它是 org.springframework.web.servlet.DispatcherServlet#initThemeResolver

/**
* Initialize the ThemeResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to a FixedThemeResolver.
*/
private void initThemeResolver(ApplicationContext context) {
try {
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.themeResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 从配置文件中获取默认的类型
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No ThemeResolver '" + THEME_RESOLVER_BEAN_NAME +
"': using default [" + this.themeResolver.getClass().getSimpleName() + "]");
}
}
}

这里的逻辑也是和上边的一样,先从 spring 容器中获取 ThemeResolver 类型实例,如果没有,则获取默认的策略,在 dispatchServlet.properties 中配置的对应的类是 org.springframework.web.servlet.theme.FixedThemeResolver。

2.3.4 initHandlerMappings() 初始化映射处理器

再看 initHandlerMappings() 初始化映射处理器,这个是非常主要的组件了,它的作用是接收外边的 url 请求,然后找到对应的处理器。看下它的实现 org.springframework.web.servlet.DispatcherServlet#initHandlerMappings:

/**
* Initialize the HandlerMappings used by this class.
* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
* we default to BeanNameUrlHandlerMapping.
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 判断是否需要发现全部的映射
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 从 spring 容器中查找所有的 HandlerMapping 类型实例
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
// 对 HandlerMapping 实例进行排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// 处理器映射器为空,则获取默认的配置策略
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
// 从配置文件中获取默认的类型
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
// 配置解析路径标识
for (HandlerMapping mapping : this.handlerMappings) {
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}

看下逻辑:

  1. 先从 spring 容器中获取全部的 HandlerMapping 实例;
  2. 如果容器中没有 HandlerMapping 实例,那就调用 getDefaultStrategies() 从dispatchSerlvet.properties 配置文件中获取默认配置;
  3. 遍历获取到的映射处理器实例,判断是否需要使用路径匹配。

dispatchSerlvet.properties 配置文件中默认的配置有 BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、RouterFunctionMapping。

我看看下这三个类实现,它们都是 HandlerMapping 接口的实现类。

2.3.4.1 HandlerMapping 映射处理器

HandlerMapping 接口全类名为 org.springframework.web.servlet.HandlerMapping,它的类图是:

HandlerMapping 接口的有两个方法,其中 getHandler() 方法就是从请求中来获取到对应的处理器。我们看下它的子类是如何实现的。

2.3.4.2 AbstractHandlerMapping 的 getHandler() 方法

看下 org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler 方法:

/**
* 根据给定的请求寻找处理器。
*
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取处理器
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// handler 是 String 类型
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 获取处理器执行链
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
// 处理跨域配置源
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
if (getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
config = (globalConfig != null ? globalConfig.combine(config) : config);
}
if (config != null) {
config.validateAllowCredentials();
}
// 获取跨域处理器执行链
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
/**
* 构建一个处理器执行链,它包含了一系列可用的拦截器。
*
* Build a {@link HandlerExecutionChain} for the given handler, including
* applicable interceptors.
* <p>The default implementation builds a standard {@link HandlerExecutionChain}
* with the given handler, the common interceptors of the handler mapping, and any
* {@link MappedInterceptor MappedInterceptors} matching to the current request URL. Interceptors
* are added in the order they were registered. Subclasses may override this
* in order to extend/rearrange the list of interceptors.
* <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
* pre-built {@link HandlerExecutionChain}. This method should handle those
* two cases explicitly, either building a new {@link HandlerExecutionChain}
* or extending the existing chain.
* <p>For simply adding an interceptor in a custom subclass, consider calling
* {@code super.getHandlerExecutionChain(handler, request)} and invoking
* {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
* @param handler the resolved handler instance (never {@code null})
* @param request current HTTP request
* @return the HandlerExecutionChain (never {@code null})
* @see #getAdaptedInterceptors()
*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 创建一个处理器执行链
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 把拦截器添加到处理器上
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;
}

整理下主要的逻辑:

  1. 执行 getHandlerInternal() 方法获取处理器;
  2. 包装处理器为一个 HandlerExecutionChain 处理器执行器链;
  3. 针对跨域请求在进行包装处理器执行器。
  4. 返回执行器。

它的 getHandlerInternal() 是一个抽象的模板方法,看看子类是如何实现的。

2.3.4.3 AbstractUrlHandlerMapping 类的 getHandlerInternal() 方法

org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#getHandlerInternal 方法:

/**
* Look up a handler for the URL path of the given request.
* @param request current HTTP request
* @return the handler instance, or {@code null} if none found
*/
@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 寻找路径
String lookupPath = initLookupPath(request);
Object handler;
if (usesPathPatterns()) {
RequestPath path = ServletRequestPathUtils.getParsedRequestPath(request);
handler = lookupHandler(path, lookupPath, request);
}
else {
handler = lookupHandler(lookupPath, request);
}
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
if (StringUtils.matchesCharacter(lookupPath, '/')) {
// root 处理器
rawHandler = getRootHandler();
}
if (rawHandler == null) {
// 默认处理器
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
// 验证处理器
validateHandler(rawHandler, request);
// 构建路径暴露执行器链
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
@Nullable
protected Object lookupHandler(
RequestPath path, String lookupPath, HttpServletRequest request) throws Exception {
// 直接匹配
Object handler = getDirectMatch(lookupPath, request);
if (handler != null) {
return handler;
}
// 通过路径匹配
// Pattern match?
List<PathPattern> matches = null;
for (PathPattern pattern : this.pathPatternHandlerMap.keySet()) {
if (pattern.matches(path)) {
matches = (matches != null ? matches : new ArrayList<>());
matches.add(pattern);
}
}
if (matches == null) {
return null;
}
if (matches.size() > 1) {
matches.sort(PathPattern.SPECIFICITY_COMPARATOR);
if (logger.isTraceEnabled()) {
logger.debug("Matching patterns " + matches);
}
}
PathPattern pattern = matches.get(0);
handler = this.pathPatternHandlerMap.get(pattern);
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 验证处理器
validateHandler(handler, request);
PathContainer pathWithinMapping = pattern.extractPathWithinPattern(path);
// 构建执行处理器链
return buildPathExposingHandler(handler, pattern.getPatternString(), pathWithinMapping.value(), null);
}
/**
* Look up a handler instance for the given URL path. This method is used
* when String pattern matching with {@code PathMatcher} is in use.
* @param lookupPath the path to match patterns against
* @param request current HTTP request
* @return a matching handler, or {@code null} if not found
* @see #exposePathWithinMapping
* @see AntPathMatcher
*/
@Nullable
protected Object lookupHandler(String lookupPath, HttpServletRequest request) throws Exception {
// 获取直接匹配
Object handler = getDirectMatch(lookupPath, request);
if (handler != null) {
return handler;
}
// 路径匹配
// Pattern match?
List<String> matchingPatterns = new ArrayList<>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, lookupPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", lookupPath)) {
matchingPatterns.add(registeredPattern + "/");
}
}
}
String bestMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(lookupPath);
if (!matchingPatterns.isEmpty()) {
matchingPatterns.sort(patternComparator);
if (logger.isTraceEnabled() && matchingPatterns.size() > 1) {
logger.trace("Matching patterns " + matchingPatterns);
}
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {
handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
if (handler == null) {
throw new IllegalStateException(
"Could not find handler for best pattern match [" + bestMatch + "]");
}
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 验证处理器
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, lookupPath);
// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
// for all of them
Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, lookupPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) {
logger.trace("URI variables " + uriTemplateVariables);
}
// 绑定路径暴露处理器
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}
// No handler found...
return null;
}

逻辑:

  1. 根据 request 初始化 path;
  2. 执行 lookupHandler() 方法获取处理器;
    1. 直接匹配,从 handlerMap 中直接获取处理器,如果找到则直接返回;
    2. 如果没有找到则通过路径匹配查找对应的处理器;
    3. 验证处理器;
    4. 构建执行器链。
  3. 返回处理器。

那么这个 LinkedHashMap 类型的 handlerMap 就是维护了url 与处理器之间的关系,那么它是如何初始化数据的呢?查看它的 put 方法调用处,发现是在

registerHandler() 这个方法中执行的。

2.3.4.4 AbstractUrlHandlerMapping 的 registerHandler() 注册处理器方法

org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#registerHandler(java.lang.String, java.lang.Object):

private final Map<String, Object> handlerMap = new LinkedHashMap<>();
/**
* Register the specified handler for the given URL paths.
* @param urlPaths the URLs that the bean should be mapped to
* @param beanName the name of the handler bean
* @throws BeansException if the handler couldn't be registered
* @throws IllegalStateException if there is a conflicting handler registered
*/
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
Assert.notNull(urlPaths, "URL path array must not be null");
for (String urlPath : urlPaths) {
registerHandler(urlPath, beanName);
}
}
/**
* 根据 urlpath 注册指定的处理器
*
* Register the specified handler for the given URL path.
* @param urlPath the URL the bean should be mapped to
* @param handler the handler instance or handler bean name String
* (a bean name will automatically be resolved into the corresponding handler bean)
* @throws BeansException if the handler couldn't be registered
* @throws IllegalStateException if there is a conflicting handler registered
*/
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;
// 解析处理器
// Eagerly resolve handler if referencing singleton via name.
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}
// 从处理器 map 中查找
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
if (urlPath.equals("/")) {
if (logger.isTraceEnabled()) {
logger.trace("Root mapping to " + getHandlerDescription(handler));
}
// 设置根处理器
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isTraceEnabled()) {
logger.trace("Default mapping to " + getHandlerDescription(handler));
}
// 设置默认的处理器
setDefaultHandler(resolvedHandler);
}
else {
// 保存到注册器中
this.handlerMap.put(urlPath, resolvedHandler);
if (getPatternParser() != null) {
// 路径处理器
this.pathPatternHandlerMap.put(getPatternParser().parse(urlPath), resolvedHandler);
}
if (logger.isTraceEnabled()) {
logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}

它的逻辑为:

  1. 如果参数处理器为非懒加载并且是 string 类型,则通过 spring 容器解析 bean;
  2. 从 handlerMap 映射 map 中查找 urlPath 对应的处理器,看是否存在;
  3. 如果存在则抛出异常,如果不存在则执行以下判断;
  4. 如果 url 为 “/”,则注册当前处理器为 root 处理器;
  5. 如果 url 为 “/*”,则注册当前处理器为默认处理器;
  6. 否则直接注册到 handlerMap 中,同时必要的时候注册到路径适配处理器映射中。

而 registerHandler() 方法又是在 org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping#detectHandlers 这个方法中被调用。

2.3.4.5 AbstractDetectingUrlHandlerMapping 的 detectHandlers() 发现处理器

detectHandlers() 方法为 org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping#detectHandlers:

/**
* 在当前的应用程序上下文中查找所有的处理器,并且注册
*
* Register all handlers found in the current ApplicationContext.
* <p>The actual URL determination for a handler is up to the concrete
* {@link #determineUrlsForHandler(String)} implementation. A bean for
* which no such URLs could be determined is simply not considered a handler.
* @throws org.springframework.beans.BeansException if the handler couldn't be registered
* @see #determineUrlsForHandler(String)
*/
protected void detectHandlers() throws BeansException {
// 获取 spring 容器中所有的 bean
ApplicationContext applicationContext = obtainApplicationContext();
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
// 根据 bean 名称获取 url
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
// 注册处理器
registerHandler(urls, beanName);
}
}
if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
}
}

detectHandlers() 方法流程:

  1. 从 spring 容器中获取所有的 bean;
  2. 遍历所有的 bean,执行 determineUrlsForHandler(String beanName) 方法,根据 bean 名称来获取对应的 url;
  3. 如果获取的 url 不为空,则调用 registerHandler() 方法,把注册 url 以及 bean 进行注册。

determineUrlsForHandler() 方法是由子类 BeanNameUrlHandlerMapping 实现。

先看下 determineUrlsForHandler() 方法的实现。

2.3.4.6 BeanNameUrlHandlerMapping 的 determineUrlsForHandler()

BeanNameUrlHandlerMapping 全类名为 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,它的类图:

它类实现很简单:

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
/**
* Checks name and aliases of the given bean for URLs, starting with "/".
*/
@Override
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
}

这个方法逻辑为:

  1. 判断 bean 的名称是否是以 “/” 开头;
  2. 如果是以 “/” 开头,则添加到结果集合中;
  3. 再从 spring 容器中获取 bean 的别名,遍历别名是否是以 “/” 开头,如果是则保存到结果集;
  4. 最后返回结果集。

再看下 detectHandlers() 方法它是被此类中的 initApplicationContext() 方法所调用:

/**
* Calls the {@link #detectHandlers()} method in addition to the
* superclass's initialization.
*/
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
// 初始化容器的时候进行注册处理器
detectHandlers();
}

它重写了父类 org.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext 方法,在初始化容器的时候,进行发现以及注册处理器;

2.3.4.8 AbstractHandlerMapping 的 initApplicationContext() 初始化容器方法

org.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext:

private final List<Object> interceptors = new ArrayList<>();
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();
/**
* Initializes the interceptors.
* @see #extendInterceptors(java.util.List)
* @see #initInterceptors()
*/
@Override
protected void initApplicationContext() throws BeansException {
// 扩展拦截器
extendInterceptors(this.interceptors);
// 发现映射拦截器
detectMappedInterceptors(this.adaptedInterceptors);
// 初始化拦截器
initInterceptors();
}
/**
* Extension hook that subclasses can override to register additional interceptors,
* given the configured interceptors (see {@link #setInterceptors}).
* <p>Will be invoked before {@link #initInterceptors()} adapts the specified
* interceptors into {@link HandlerInterceptor} instances.
* <p>The default implementation is empty.
* @param interceptors the configured interceptor List (never {@code null}), allowing
* to add further interceptors before as well as after the existing interceptors
*/
protected void extendInterceptors(List<Object> interceptors) {
}
/**
* Detect beans of type {@link MappedInterceptor} and add them to the list
* of mapped interceptors.
* <p>This is called in addition to any {@link MappedInterceptor}s that may
* have been provided via {@link #setInterceptors}, by default adding all
* beans of type {@link MappedInterceptor} from the current context and its
* ancestors. Subclasses can override and refine this policy.
* @param mappedInterceptors an empty list to add to
*/
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
/**
* Initialize the specified interceptors adapting
* {@link WebRequestInterceptor}s to {@link HandlerInterceptor}.
* @see #setInterceptors
* @see #adaptInterceptor
*/
protected void initInterceptors() {
// 初始化拦截器
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
// 添加适配器拦截器
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}

这个方法主要是注册和初始化拦截器:

  1. 调用 extendInterceptors() 方法,扩展拦截器(无实现);
  2. 调用 detectMappedInterceptors() 方法,发现映射拦截器:从 spring 容器中加载 MappedInterceptor 实例并添加到 adaptedInterceptors 集合中;
  3. 调用 initInterceptors() 方法,初始化拦截器:将 interceptors 添加到 adaptedInterceptors 集合中。

2.3.4.9 AbstractHandlerMethodMapping 的 getHandlerInternal() 方法

我们现在回来,该看 AbstractHandlerMethodMapping 的 getHandlerInternal() 方法了 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal:

/**
* Look up a handler method for the given request.
*/
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 初始化寻找的路径
String lookupPath = initLookupPath(request);
// 获取锁
this.mappingRegistry.acquireReadLock();
try {
// 寻找处理器方法 HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// 通过执行器方法创建解析器 bean
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
/**
* Look up the best-matching handler method for the current request.
* If multiple matches are found, the best match is selected.
* @param lookupPath mapping lookup path within the current servlet mapping
* @param request the current request
* @return the best-matching handler method, or {@code null} if no match
* @see #handleMatch(Object, String, HttpServletRequest)
* @see #handleNoMatch(Set, String, HttpServletRequest)
*/
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 获取映射
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
// 添加映射
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// 添加映射
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
// 排序
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
// 设置属性
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
// 处理匹配
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
}

它的逻辑:

  1. 初始化寻找的路径;
  2. 执行 lookupHandlerMethod() 查找处理器方法;
    1. 通过 MappingRegistry 类型 mappingRegistry 获取匹配路径;
    2. 调用 addMatchingMappings() 方法,获取匹配的映射;
    3. 获取最佳匹配器,设置匹配信息到请求属性中;
    4. 返回处理器方法。
  3. 返回处理器方法。

这边的重点是 mappingRegistry 是如何初始化的,看下它初始化的地方 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod:

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 注册处理器方法
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
/**
* Determine the type of the specified candidate bean and call
* {@link #detectHandlerMethods} if identified as a handler type.
* <p>This implementation avoids bean creation through checking
* {@link org.springframework.beans.factory.BeanFactory#getType}
* and calling {@link #detectHandlerMethods} with the bean name.
* @param beanName the name of the candidate bean
* @since 5.1
* @see #isHandler
* @see #detectHandlerMethods
*/
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
// 发现处理器方法
detectHandlerMethods(beanName);
}
}
/**
* Detects handler methods at initialization.
* @see #initHandlerMethods
*/
@Override
public void afterPropertiesSet() {
// 初始化处理器方法
initHandlerMethods();
}
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #getCandidateBeanNames()
* @see #processCandidateBean
* @see #handlerMethodsInitialized
*/
protected void initHandlerMethods() {
// 处理候选的 bean
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
// 初始化候选方法
handlerMethodsInitialized(getHandlerMethods());
}

registerHandlerMethod() 方法的调用栈为:

AbstractHandlerMethodMapping.detectHandlerMethods(Object)  (org.springframework.web.servlet.handler)
AbstractHandlerMethodMapping.processCandidateBean(String)  (org.springframework.web.servlet.handler)
AbstractHandlerMethodMapping.initHandlerMethods()  (org.springframework.web.servlet.handler)
AbstractHandlerMethodMapping.afterPropertiesSet()  (org.springframework.web.servlet.handler)
...省略...

可以知道,它是实现了 InitializingBean 接口的 afterPropertiesSet() 方法,来执行注册 mappingRegistry 属性的。里边调用了 initHandlerMethods() 方法初始化执行器方法。

我看下 initHandlerMethods() 的注册逻辑:

  1. 从 spring 容器中获取所有的 bean;
  2. 判断 bean 是否为一个处理器,isHandler()
  3. 执行 processCandidateBean() 方法处理候选者,内部执行 detectHandlerMethods(String beanName) 方法;
    1. 获取处理器类型;
    2. 通过 MethodIntrospector.selectMethods() 方法获取方法与结果映射关系;
    3. 遍历映射关系,进行 mappingRegistry 注册处理器。

我们看下它是怎么注册的 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register:

public void register(T mapping, Object handler, Method method) {
// Assert that the handler method is not a suspending one.
if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
Class<?>[] types = method.getParameterTypes();
if ((types.length > 0) && "kotlin.coroutines.Continuation".equals(types[types.length - 1].getName())) {
throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
}
}
this.readWriteLock.writeLock().lock();
try {
// 创建一个 HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
// 验证方法映射
validateMethodMapping(handlerMethod, mapping);
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
}
// 添加映射
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
// 配置
CorsConfiguration config = initCorsConfiguration(handler, method, mapping);
if (config != null) {
config.validateAllowCredentials();
this.corsLookup.put(handlerMethod, config);
}
// 注册
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}

这里会创建一个 HandlerMethod 对象来注册起来。

isHandler()、getMappingForMethod()、registerHandlerMethod() 方法都是交给了子类 RequestMappingHandlerMapping 实现。

2.3.4.10 RequestMappingHandlerMapping 请求映射处理器映射

同样看下它的类图:

看下它的几个方法的实现:

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#isHandler

@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

这里判断了目标类型是否有@Controller 注解或者 @RequestMapping 注解。

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#getMappingForMethod

@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 创建一个请求映射信息
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
/**
* Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)},
* supplying the appropriate custom {@link RequestCondition} depending on whether
* the supplied {@code annotatedElement} is a class or method.
* @see #getCustomTypeCondition(Class)
* @see #getCustomMethodCondition(Method)
*/
@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
// 请求映射
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
// 创建一个请求映射
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

这个方法是创建一个 RequestMappingInfo 对象返回。

2.3.5 initHandlerAdapters() 初始化处理器适配器

初始化处理器适配器 org.springframework.web.servlet.DispatcherServlet#initHandlerAdapters:

/**
* Initialize the HandlerAdapters used by this class.
* <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
* we default to SimpleControllerHandlerAdapter.
*/
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<>(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");
}
}
}

这里的逻辑也是先从 spring 容器中获取 HandlerAdapter 类型的实例,如果没有的话则执行从默认的 dispatchServlet.properties 中读取。

默认的实现类有 HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter、HandlerFunctionAdapter。

这个处理器适配器有什么用呢?它是在 DispatchServlet 执行的时候用到,通过 url 获取到执行器,然后再通过执行器适配器执行目标方法。

2.3.5.1 HandlerAdapter 处理器适配器

org.springframework.web.servlet.HandlerAdapter

/**
* Given a handler instance, return whether or not this {@code HandlerAdapter}
* can support it. Typical HandlerAdapters will base the decision on the handler
* type. HandlerAdapters will usually only support one handler type each.
* <p>A typical implementation:
* <p>{@code
* return (handler instanceof MyHandler);
* }
* @param handler the handler object to check
* @return whether or not this object can use the given handler
*/
boolean supports(Object handler);
/**
* Use the given handler to handle this request.
* The workflow that is required may vary widely.
* @param request current HTTP request
* @param response current HTTP response
* @param handler the handler to use. This object must have previously been passed
* to the {@code supports} method of this interface, which must have
* returned {@code true}.
* @throws Exception in case of errors
* @return a ModelAndView object with the name of the view and the required
* model data, or {@code null} if the request has been handled directly
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* Same contract as for HttpServlet's {@code getLastModified} method.
* Can simply return -1 if there's no support in the handler class.
* @param request current HTTP request
* @param handler the handler to use
* @return the lastModified value for the given handler
* @see javax.servlet.http.HttpServlet#getLastModified
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified
*/
long getLastModified(HttpServletRequest request, Object handler);

supports() 方法是判断处理器适配器是否支持处理器,handle() 方法是执行处理器。

2.3.5.2 HttpRequestHandlerAdapter

org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter

/**
* Adapter to use the plain {@link org.springframework.web.HttpRequestHandler}
* interface with the generic {@link org.springframework.web.servlet.DispatcherServlet}.
* Supports handlers that implement the {@link LastModified} interface.
*
* <p>This is an SPI class, not used directly by application code.
*
* @author Juergen Hoeller
* @since 2.0
* @see org.springframework.web.servlet.DispatcherServlet
* @see org.springframework.web.HttpRequestHandler
* @see LastModified
* @see SimpleControllerHandlerAdapter
*/
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
// 判断 handler 是否 HttpRequestHandler 子类
return (handler instanceof HttpRequestHandler);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 将处理器强转为 HttpRequestHandler,执行请求 handleRequest
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}

2.3.5.3 SimpleControllerHandlerAdapter

org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter:

/**
* Adapter to use the plain {@link Controller} workflow interface with
* the generic {@link org.springframework.web.servlet.DispatcherServlet}.
* Supports handlers that implement the {@link LastModified} interface.
*
* <p>This is an SPI class, not used directly by application code.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see org.springframework.web.servlet.DispatcherServlet
* @see Controller
* @see LastModified
* @see HttpRequestHandlerAdapter
*/
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
// 判断 handler 是否为 Controller 子类
return (handler instanceof Controller);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 将 handler 强转为 Controller 类型,执行 handleRequest 方法
return ((Controller) handler).handleRequest(request, response);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}

2.3.5.4 RequestMappingHandlerAdapter(重点)

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter:

/**
* 构造器
*/
public RequestMappingHandlerAdapter() {
// 初始化消息转化器
this.messageConverters = new ArrayList<>(4);
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
if (!shouldIgnoreXml) {
try {
this.messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
}
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
// 初始化 ControllerAdvice
initControllerAdviceCache();
// 参数解析器
if (this.argumentResolvers == null) {
// 获取默认的参数解析器
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 绑定参数解析器
if (this.initBinderArgumentResolvers == null) {
// 获取默认的初始化绑定参数解析器
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 返回值处理器
if (this.returnValueHandlers == null) {
// 获取默认返回值处理器
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
// 查找有 @ControllerAdvice 注解标注的类,注册为 ControllerAdviceBean
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
// 遍历
for (ControllerAdviceBean adviceBean : adviceBeans) {
Class<?> beanType = adviceBean.getBeanType();
if (beanType == null) {
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
}
// 查找标记有 @ModelAttribute 注解的方法
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
// 放入缓存
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
}
// 查找有 @InitBinder 注解的方法
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
// 放入缓存
this.initBinderAdviceCache.put(adviceBean, binderMethods);
}
//  注册有 @RequestBodyAdvice 或者 @ResponseBodyAdvice 注解标记的 adviceBean
if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
// 放入缓存
requestResponseBodyAdviceBeans.add(adviceBean);
}
}
if (!requestResponseBodyAdviceBeans.isEmpty()) {
// 保存起来
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
if (logger.isDebugEnabled()) {
int modelSize = this.modelAttributeAdviceCache.size();
int binderSize = this.initBinderAdviceCache.size();
int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
logger.debug("ControllerAdvice beans: none");
}
else {
logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
}
}
}
/**
* 获取默认的参数解析器
*
* Return the list of argument resolvers to use including built-in resolvers
* and custom resolvers provided via {@link #setCustomArgumentResolvers}.
*/
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
/**
* 获取默认的初始化绑定参数解析器
*
* Return the list of argument resolvers to use for {@code @InitBinder}
* methods including built-in and custom resolvers.
*/
private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(20);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
return resolvers;
}
/**
* 返回默认返回值解析器
*
* Return the list of return value handlers to use including built-in and
* custom handlers provided via {@link #setReturnValueHandlers}.
*/
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ServletModelAttributeMethodProcessor(false));
// 请求相应 body 方法处理器
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ServletModelAttributeMethodProcessor(true));
}
return handlers;
}
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// 同步请求
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
// 执行处理器方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 执行处理器方法
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 执行目标映射请求的处理
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
// 应用缓存
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
// 准备响应,设置 response 属性信息
prepareResponse(response);
}
}
return mav;
}
/**
* 执行请求映射的逻辑,返回 ModelAndView 对象。
*
* Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
* if view resolution is required.
* @since 4.2
* @see #createInvocableHandlerMethod(HandlerMethod)
*/
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 创建一个 ServletWebRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// web 数据绑定工厂
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// model 工厂
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 执行器方法
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 模型与视图容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 初始化 model
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 异步 web 请求
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// web 异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 执行器方法执行请求处理
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 返回模型与视图
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
  1. 我们先它的构造器方法 RequestMappingHandlerAdapter(),它会初始化一些消息转化器 HttpMessageConverter;
  2. 它的初始化方法 afterPropertiesSet();
    1. 先初始化标注有 @ControllerAdvice、@ModelAttribute、@InitBinder、@RequestBodyAdvice 或者 @ResponseBodyAdvice的类和方法信息,保存起来;
    2. 初始化参数解析器 HandlerMethodArgumentResolver;
    3. 初始化绑定参数解析器 HandlerMethodArgumentResolver;
    4. 初始化返回值处理器 HandlerMethodReturnValueHandler。
  3. handleInternal() 方法是模板方法,返回一个 ModelAndView对象;
    1. 执行 invokeHandlerMethod() 方法,执行处理处理器方法;
      1. 创建 ServletInvocableHandlerMethod 类型实例;
      2. 为执行处理器方法实例设置 WebDataBinderFactory、参数解析器、返回值解析器、数据绑定、参数名称发现器;
      3. 创建 ModelAndViewContainer 实例;
      4. 创建异步 web 请求 AsyncWebRequest 实例;
      5. 创建 web 异步管理器实例 WebAsyncManager;
      6. 执行器方法执行请求处理 invocableMethod.invokeAndHandle(webRequest, mavContainer);
      7. 执行 getModelAndView() 创建 ModelAndView 实例返回。
    2. 执行applyCacheSeconds() 方法应用缓存;
    3. 执行 prepareResponse() 方法,设置响应属性信息。

2.3.6 initHandlerExceptionResolvers() 初始化处理器异常解析器

org.springframework.web.servlet.DispatcherServlet#initHandlerExceptionResolvers:

/**
* Initialize the HandlerExceptionResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to no exception resolver.
*/
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
// We keep HandlerExceptionResolvers in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
else {
try {
HandlerExceptionResolver her =
context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, no HandlerExceptionResolver is fine too.
}
}
// Ensure we have at least some HandlerExceptionResolvers, by registering
// default HandlerExceptionResolvers if no other resolvers are found.
if (this.handlerExceptionResolvers == null) {
// 从配置文件中获取默认的类型
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}

它的逻辑也是从 spring容器中获取 HandlerExceptionResolver 实例,如果没有则从 dispatchServlet.properties 配置文件读取默认配置信息;

默认的配置有 ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver。

2.3.6.1 HandlerExceptionResolver 处理器异常解析器

org.springframework.web.servlet.HandlerExceptionResolver:

public interface HandlerExceptionResolver {
/**
* Try to resolve the given exception that got thrown during handler execution,
* returning a {@link ModelAndView} that represents a specific error page if appropriate.
* <p>The returned {@code ModelAndView} may be {@linkplain ModelAndView#isEmpty() empty}
* to indicate that the exception has been resolved successfully but that no view
* should be rendered, for instance by setting a status code.
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler, or {@code null} if none chosen at the
* time of the exception (for example, if multipart resolution failed)
* @param ex the exception that got thrown during handler execution
* @return a corresponding {@code ModelAndView} to forward to,
* or {@code null} for default processing in the resolution chain
*/
@Nullable
ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}

执行器处理器解析器接口提供一个方法,就是处理异常返回一个 ModelAndView。

2.3.7 initRequestToViewNameTranslator() 初始化请求试图名称转化器

org.springframework.web.servlet.DispatcherServlet#initRequestToViewNameTranslator

/**
* Initialize the RequestToViewNameTranslator used by this servlet instance.
* <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
*/
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
this.viewNameTranslator =
context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.viewNameTranslator);
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 从配置文件中获取默认的类型
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
if (logger.isTraceEnabled()) {
logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
}
}
}

从 spring 容器中查找 RequestToViewNameTranslator 实例,如果没有则从 dispatchServlet.properties 配置文件读取默认配置信息;

默认的配置类为 org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator。

RequestToViewNameTranslator 接口主要的功能是根据请求返回一个视图名称。

2.3.8 initViewResolvers() 初始化视图解析器

org.springframework.web.servlet.DispatcherServlet#initViewResolvers:

/**
* Initialize the ViewResolvers used by this class.
* <p>If no ViewResolver beans are defined in the BeanFactory for this
* namespace, we default to InternalResourceViewResolver.
*/
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<>(matchingBeans.values());
// We keep ViewResolvers in sorted order.
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
else {
try {
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default ViewResolver later.
}
}
// Ensure we have at least one ViewResolver, by registering
// a default ViewResolver if no other resolvers are found.
if (this.viewResolvers == null) {
// 从配置文件中获取默认的类型
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No ViewResolvers declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}

从 spring 容器中查找 ViewResolver 实例,如果没有则从 dispatchServlet.properties 配置文件读取默认配置信息;

默认的配置类为 org.springframework.web.servlet.view.InternalResourceViewResolver。

2.3.8.1 ViewResolver 视图解析器

org.springframework.web.servlet.ViewResolver

ViewResolver 接口提供了一个方法 resolveViewName(),根据视图名称和 local 参数来获取一个 View。

2.3.9 initFlashMapManager() 初始化刷新映射管理器

/**
* Initialize the {@link FlashMapManager} used by this servlet instance.
* <p>If no implementation is configured then we default to
* {@code org.springframework.web.servlet.support.DefaultFlashMapManager}.
*/
private void initFlashMapManager(ApplicationContext context) {
try {
this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.flashMapManager);
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 从配置文件中获取默认的类型
this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
if (logger.isTraceEnabled()) {
logger.trace("No FlashMapManager '" + FLASH_MAP_MANAGER_BEAN_NAME +
"': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");
}
}
}

3. DispatchServlet 执行

它的执行方法为 org.springframework.web.servlet.DispatcherServlet#doDispatch:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 请求
HttpServletRequest processedRequest = request;
// 处理器执行链
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取处理器
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取处理器适配器
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 应用处理器拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 处理器适配器实际的执行
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 应用默认的视图
applyDefaultViewName(processedRequest, mv);
// 处理器拦截器执行后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理结果视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

主要的处理流程:

  1. 执行 getHandler() 获取处理器,根据请求去从处理器映射器中查找匹配的处理器,返回一个 HandlerExecutionChain;
  2. 执行 getHandlerAdapter() 获取处理器适配器,从注册的 HandlerAdapter 中查找支持处理器的适配器;
  3. 执行 applyPreHandle() 应用处理器拦截器的 preHandle() 方法,如果执行失败,则执行拦截器的的 afterCompletion() 方法,最后结束调用;如果执行成功则继续下面的流程;
  4. 执行执行器适配器的 handle() 方法,去执行对应的执行器,返回一个视图与模型实例;
  5. 执行 applyDefaultViewName() 应用默认的视图名称;
  6. 执行 applyPostHandle() 应用执行器拦截器的 postHandle() 方法;
  7. 执行 processDispatchResult() 处理结果;
    1. 如果上述过程有异常抛出,则执行异常处理器来处理异常返回模型与视图实例;
    2. 执行 render() 方法,解析视图,渲染结果;
    3. 最后执行执行器拦截器的 triggerAfterCompletion 方法。

这就是 dispatchServlet 的全部的流程。

微信扫一扫,分享到朋友圈

springmvc 核心流程源码分析

如何避免在Jupyter Lab中重复造轮子?

上一篇

刘作虎:今年没有一加 8T Pro

下一篇

你也可能喜欢

springmvc 核心流程源码分析

长按储存图像,分享给朋友