Spring MVC 初始化

1. DispatcherServlet 的初始化流程

DispatcherServlet 是 Spring MVC 的核心入口,负责接收 HTTP 请求并将其分发给相应的处理器。它的初始化过程从 HttpServlet 的生命周期方法 init() 开始。

1.1 HttpServletBean 的 init() 方法

DispatcherServlet 继承自 FrameworkServlet,而 FrameworkServlet 又继承自 HttpServletBeanHttpServletBeaninit() 方法是初始化的起点。

@Override
public final void init() throws ServletException {
    // 1. 解析 Servlet 的初始化参数,并将其注入到 DispatcherServlet 的 Bean 属性中
    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
    ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
    bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
    initBeanWrapper(bw);
    bw.setPropertyValues(pvs, true);

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

1.2 FrameworkServlet 的 initServletBean() 方法

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

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

1.3 initWebApplicationContext() 方法

initWebApplicationContext()FrameworkServlet 的核心方法,负责创建或获取 WebApplicationContext

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. 触发刷新事件
    if (!this.refreshEventReceived) {
        onRefresh(wac);
    }

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

2. DispatcherServlet 的策略组件初始化

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

2.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.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
    

2.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
    

2.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
    

3. 总结

Spring MVC 的初始化过程可以概括为以下几个步骤:

  1. DispatcherServlet 初始化:从 HttpServletBeaninit() 方法开始,解析 Servlet 配置并注入属性。
  2. WebApplicationContext 初始化:创建或获取 Spring 的上下文环境。
  3. 策略组件初始化:在 onRefresh() 方法中初始化 HandlerMappingHandlerAdapterViewResolver 等核心组件。
  4. 默认策略:如果没有显式配置组件,Spring MVC 会使用 DispatcherServlet.properties 中定义的默认策略。

通过深入源码分析,我们可以清晰地看到 Spring MVC 的初始化流程及其核心组件的加载过程。这为我们在实际开发中自定义和扩展 Spring MVC 提供了坚实的基础。

posted @   CyrusHuang  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· RFID实践——.NET IoT程序读取高频RFID卡/标签
点击右上角即可分享
微信分享提示