SpringMVC初始化原理剖析和源码跟踪

发布于:2025-03-23 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、 DispatcherServlet 的初始化流程

DispatcherServlet 是 Spring MVC 的核心入口,负责接收 HTTP 请求并将其分发给相应的处理器。大致流程就这么简单。

1、DispatcherServlet的继承关系

DispatcherServlet 继承自 FrameworkServlet,而 FrameworkServlet 又继承自HttpServletBean 又继承 HttpServlet。我们来看图。
在这里插入图片描述

1、 HttpServletBean 的 init() 方法

DispatcherServlet 继承自 FrameworkServlet,而 FrameworkServlet 又继承自 HttpServletBeanHttpServletBeaninit() 方法是初始化的起点,然后调用的 FrameworkServletinitServletBean()方法。我们接着往下看。

@Override
	public final void init() throws ServletException {

		// 1. 解析 Servlet 的初始化参数,并将其注入到 DispatcherServlet 的 Bean 属性中
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				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;
			}
		}

		//2. 调用子类的初始化方法,具体的初始化方法,是从FrameworkServlet开始。
		initServletBean();
	}
  • ServletConfigPropertyValues:解析 web.xml 中配置的 Servlet 初始化参数(如 contextConfigLocation)。
  • BeanWrapper:将解析后的参数注入到 DispatcherServlet 的 Bean 属性中。
  • initServletBean():调用子类 FrameworkServlet 的初始化方法。

2、 FrameworkServlet 的 initServletBean() 方法

FrameworkServletinitServletBean() 方法负责初始化 Spring 的 WebApplicationContext

@Override
protected final void initServletBean() throws ServletException {
    // 初始化 WebApplicationContext
    this.webApplicationContext = initWebApplicationContext();
    initFrameworkServlet();
}
  • initWebApplicationContext():创建或获取 WebApplicationContext
  • initFrameworkServlet():空方法,留给子类扩展。

3、initWebApplicationContext() 方法

initWebApplicationContext()FrameworkServlet 的核心方法,负责创建或获取 WebApplicationContext。如果没有显式配置 WAC,则从父容器或默认路径加载。在 initWebApplicationContext()方法完成后,会调用 DispatcherServletonRefresh() 方法。

protected WebApplicationContext initWebApplicationContext() {
    // 1. 获取根 WebApplicationContext(通常是通过 ContextLoaderListener 加载的)
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    // 2. 如果已经通过构造方法或 setter 注入了 WebApplicationContext,则直接使用
    if (this.webApplicationContext != null) {
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            if (!cwac.isActive()) {
                if (cwac.getParent() == null) {
                    cwac.setParent(rootContext);
                }
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    // 3. 如果没有显式注入 WebApplicationContext,则尝试从 ServletContext 中查找
    if (wac == null) {
        wac = findWebApplicationContext();
    }
    // 4. 如果仍然没有找到,则创建一个新的 WebApplicationContext
    if (wac == null) {
        wac = createWebApplicationContext(rootContext);
    }
    // 5. 触发刷新事件,调用 DispatcherServlet 的 onRefresh() 方法。
    if (!this.refreshEventReceived) {
        onRefresh(wac);
    }

    return wac;
}
  • rootContext:通过 ContextLoaderListener 加载的根上下文(通常是 Spring 的父容器)。
  • createWebApplicationContext():创建新的 WebApplicationContext,默认实现是 XmlWebApplicationContextAnnotationConfigWebApplicationContext
  • onRefresh():在 WebApplicationContext 刷新时调用,DispatcherServlet 会在此方法中初始化各种策略组件。

二、DispatcherServlet 的策略组件初始化

DispatcherServlet 的核心功能依赖于一系列策略组件,如 HandlerMappingHandlerAdapterViewResolver 等。这些组件的初始化在 onRefresh() 方法中完成。

1、 onRefresh() 方法

onRefresh()DispatcherServlet 初始化的核心方法,负责初始化所有策略组件。

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);        // 初始化文件上传解析器
    initLocaleResolver(context);           // 初始化本地化解析器
    initThemeResolver(context);            // 初始化主题解析器
    initHandlerMappings(context);          // 初始化处理器映射器
    initHandlerAdapters(context);          // 初始化处理器适配器
    initHandlerExceptionResolvers(context); // 初始化异常解析器
    initRequestToViewNameTranslator(context); // 初始化请求到视图名的转换器
    initViewResolvers(context);            // 初始化视图解析器
    initFlashMapManager(context);          // 初始化 FlashMap 管理器
}

2、 initHandlerMappings() 方法

HandlerMapping 负责将请求映射到相应的处理器(Controller)。DispatcherServlet 会从 WebApplicationContext 中获取所有类型为 HandlerMapping 的 Bean。

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    // 1. 是否检测所有 HandlerMapping Bean
    if (this.detectAllHandlerMappings) {
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    } else {
        // 2. 只检测名为 "handlerMapping" 的 Bean
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        } catch (NoSuchBeanDefinitionException ex) {
            // 忽略,稍后会使用默认策略
        }
    }

    // 3. 如果没有找到 HandlerMapping,则使用默认策略
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    }
}
  • 默认策略:如果没有显式配置 HandlerMapping,Spring MVC 会使用 DispatcherServlet.properties 中定义的默认策略:

    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
        org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
    

3、initHandlerAdapters() 方法

HandlerAdapter 负责调用处理器(Controller)的方法。DispatcherServlet 会从 WebApplicationContext 中获取所有类型为 HandlerAdapter 的 Bean。

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

    // 1. 是否检测所有 HandlerAdapter Bean
    if (this.detectAllHandlerAdapters) {
        Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    } else {
        // 2. 只检测名为 "handlerAdapter" 的 Bean
        try {
            HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
            this.handlerAdapters = Collections.singletonList(ha);
        } catch (NoSuchBeanDefinitionException ex) {
            // 忽略,稍后会使用默认策略
        }
    }

    // 3. 如果没有找到 HandlerAdapter,则使用默认策略
    if (this.handlerAdapters == null) {
        this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
    }
}
  • 默认策略:如果没有显式配置 HandlerAdapter,Spring MVC 会使用 DispatcherServlet.properties 中定义的默认策略:

    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
    

4、 initViewResolvers() 方法

ViewResolver 负责将逻辑视图名称解析为实际的视图对象。DispatcherServlet 会从 WebApplicationContext 中获取所有类型为 ViewResolver 的 Bean。

private void initViewResolvers(ApplicationContext context) {
    this.viewResolvers = null;

    // 1. 是否检测所有 ViewResolver Bean
    if (this.detectAllViewResolvers) {
        Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, ViewResolver.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.viewResolvers = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.viewResolvers);
        }
    } else {
        // 2. 只检测名为 "viewResolver" 的 Bean
        try {
            ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
            this.viewResolvers = Collections.singletonList(vr);
        } catch (NoSuchBeanDefinitionException ex) {
            // 忽略,稍后会使用默认策略
        }
    }

    // 3. 如果没有找到 ViewResolver,则使用默认策略
    if (this.viewResolvers == null) {
        this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
    }
}
  • 默认策略:如果没有显式配置 ViewResolver,Spring MVC 会使用 DispatcherServlet.properties 中定义的默认策略:

    org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
    

当上述所有组件初始化完成后,DispatcherServlet 进入就绪状态,可以接收并分发 HTTP 请求。

三、总结

DispatcherServlet 的初始化过程是一个复杂的链式调用,核心在于通过 Web IoC 容器加载和初始化各种组件,为后续的请求分发做好准备。
Spring MVC 的初始化过程可以概括为以下几个步骤:

  1. DispatcherServlet 初始化:从 HttpServletBeaninit() 方法开始,解析 Servlet 配置并注入属性,然后调用FrameworkServletinitServletBean()方法,里面调用WebApplicationContex初始化和initFrameworkServlet()initFrameworkServlet()没有具体的实现。
  2. WebApplicationContext 初始化:创建或获取 Spring 的上下文环境,再调用DispatcherServletonRefresh()方法。
  3. 策略组件初始化:在 onRefresh() 方法中初始化 HandlerMappingHandlerAdapterViewResolver 等核心组件,各个组件如果没有显式配置组件,就会执行默认策略。
  4. 默认策略:Spring MVC 会使用 DispatcherServlet.properties 中定义的默认策略。

结束
文章结束,喜欢就给个一键三连吧,你的肯定是我最大的动力,点赞上一千我就是脑瘫也出下章。