全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-18 10 分钟 ✍️ juanwangdev

SpringMVC容器初始化与DispatcherServlet

SpringMVC采用父子容器架构,WebApplicationContext作为子容器继承根容器配置。

父子容器架构

XML
Root WebApplicationContext (Spring容器)
    - Service、Repository、DataSource等
    - ContextLoaderListener创建
        ↓
Servlet WebApplicationContext (SpringMVC容器)
    - Controller、HandlerMapping、HandlerAdapter等
    - DispatcherServlet创建

ContextLoaderListener初始化

配置方式

Java
<!-- web.xml -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.example.config.RootConfig</param-value>
</context-param>

源码解析

Java
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        // 初始化根WebApplicationContext
        initWebApplicationContext(event.getServletContext());
    }
}

public class ContextLoader {
    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        // 检查是否已存在根容器
        if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
            throw new IllegalStateException("已存在根容器");
        }

        try {
            // 创建根容器
            WebApplicationContext context = createWebApplicationContext(servletContext);

            // 配置并刷新
            configureAndRefreshWebApplicationContext(context, servletContext);

            // 存入ServletContext
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);

            return context;
        } catch (RuntimeException ex) {
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
            throw ex;
        }
    }
}

DispatcherServlet容器创建

FrameworkServlet.initWebApplicationContext()

Java
protected WebApplicationContext initWebApplicationContext() {
    // 获取根容器
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());

    WebApplicationContext wac = null;

    // 1. 如果已注入WebApplicationContext
    if (this.webApplicationContext != null) {
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            if (!((ConfigurableWebApplicationContext) wac).isActive()) {
                ((ConfigurableWebApplicationContext) wac).setParent(rootContext);
                configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext) wac);
            }
        }
    }

    // 2. 查找已存在的WebApplicationContext
    if (wac == null) {
        wac = findWebApplicationContext();
    }

    // 3. 创建新的WebApplicationContext
    if (wac == null) {
        wac = createWebApplicationContext(rootContext);
    }

    // 4. 触发onRefresh
    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            onRefresh(wac);
        }
    }

    return wac;
}

createWebApplicationContext()

Java
protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
    Class<?> contextClass = getContextClass();
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
        throw new ApplicationContextException("Invalid context class");
    }

    ConfigurableWebApplicationContext wac =
        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    wac.setEnvironment(getEnvironment());
    wac.setParent(parent); // 设置父容器
    wac.setServletContext(getServletContext());

    String configLocation = getContextConfigLocation();
    if (configLocation != null) {
        wac.setConfigLocation(configLocation);
    }

    configureAndRefreshWebApplicationContext(wac);
    return wac;
}

父子容器Bean访问

Java
// 子容器可访问父容器Bean,父容器不可访问子容器Bean
public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {

    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    protected <T> T doGetBean(String name, Class<T> requiredType,
            Object[] args, boolean typeCheckOnly) {

        // 1. 先检查本容器
        Object bean = getSingleton(name);
        if (bean != null) {
            return (T) bean;
        }

        // 2. 检查父容器
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null) {
            if (args != null) {
                return (T) parentBeanFactory.getBean(name, args);
            } else {
                return (T) parentBeanFactory.getBean(name, requiredType);
            }
        }

        // 3. 创建Bean
        return createBean(name, requiredType, args);
    }
}

Spring Boot自动配置

DispatcherServletAutoConfiguration

Java
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class DispatcherServletAutoConfiguration {

    @Configuration
    @Conditional(DefaultDispatcherServletCondition.class)
    @ConditionalOnClass(Servlet.class)
    protected static class DispatcherServletConfiguration {

        @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
        @ConditionalOnMissingBean
        public DispatcherServlet dispatcherServlet() {
            DispatcherServlet dispatcherServlet = new DispatcherServlet();
            dispatcherServlet.setDispatchOptionsRequest(true);
            dispatcherServlet.setDispatchTraceRequest(true);
            dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
            return dispatcherServlet;
        }
    }

    @Configuration
    @Conditional(ServletRegistrationCondition.class)
    @ConditionalOnClass(Servlet.class)
    @EnableConfigurationProperties(WebMvcProperties.class)
    protected static class DispatcherServletRegistrationConfiguration {

        @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
        @ConditionalOnMissingBean(value = DispatcherServlet.class, ignored = DispatcherServlet.class)
        public DispatcherServletRegistrationBean dispatcherServletRegistration(
                WebMvcProperties webMvcProperties, DispatcherServlet dispatcherServlet) {
            DispatcherServletRegistrationBean registration =
                new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
            registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
            registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
            return registration;
        }
    }
}

ServletWebServerApplicationContext

Java
public class ServletWebServerApplicationContext extends GenericWebApplicationContext
        implements WebServerApplicationContext {

    private volatile WebServer webServer;

    @Override
    public void refresh() {
        try {
            // 创建WebServer(内嵌Tomcat/Jetty等)
            createWebServer();

            super.refresh();

            // 启动WebServer
            startWebServer();
        } catch (Exception ex) {
            stopAndReleaseWebServer();
            throw ex;
        }
    }

    private void createWebServer() {
        ServletWebServerFactory factory = getWebServerFactory();
        this.webServer = factory.getWebServer(getServletContextInitializer());
    }
}

WebApplicationContext类型

类型说明适用场景
XmlWebApplicationContextXML配置传统XML配置
AnnotationConfigWebApplicationContext注解配置注解驱动开发
GroovyWebApplicationContextGroovy配置Groovy DSL配置

DispatcherServlet配置属性

Java
// FrameworkServlet关键属性
public class FrameworkServlet extends HttpServletBean {
    private String contextClass; // WebApplicationContext类型
    private String contextConfigLocation; // 配置位置
    private WebApplicationContext webApplicationContext; // 上下文实例
    private boolean publishContext = true; // 是否发布到ServletContext
    private boolean publishEvents = true; // 是否发布事件
}

多DispatcherServlet配置

text
@Configuration
public class MultiServletConfig {
    @Bean
    public DispatcherServlet apiDispatcherServlet() {
        DispatcherServlet servlet = new DispatcherServlet();
        servlet.setContextClass(AnnotationConfigWebApplicationContext.class);
        servlet.setContextConfigLocation("com.example.config.ApiConfig");
        return servlet;
    }

    @Bean
    public ServletRegistrationBean<DispatcherServlet> apiServletRegistration() {
        ServletRegistrationBean<DispatcherServlet> registration =
            new ServletRegistrationBean<>(apiDispatcherServlet(), "/api/*");
        registration.setName("apiDispatcher");
        registration.setLoadOnStartup(1);
        return registration;
    }

    @Bean
    public DispatcherServlet webDispatcherServlet() {
        DispatcherServlet servlet = new DispatcherServlet();
        servlet.setContextClass(AnnotationConfigWebApplicationContext.class);
        servlet.setContextConfigLocation("com.example.config.WebConfig");
        return servlet;
    }

    @Bean
    public ServletRegistrationBean<DispatcherServlet> webServletRegistration() {
        ServletRegistrationBean<DispatcherServlet> registration =
            new ServletRegistrationBean<>(webDispatcherServlet(), "/web/*");
        registration.setName("webDispatcher");
        registration.setLoadOnStartup(2);
        return registration;
    }
}

容器初始化流程图

text
Servlet容器启动
        ↓
ContextLoaderListener.contextInitialized()
    ↓
ContextLoader.initWebApplicationContext()
    ↓ 创建根容器
    ↓ 配置RootConfig
    ↓ refresh()
    ↓ 存入ServletContext
        ↓
DispatcherServlet.init()
    ↓
HttpServletBean.init() - 解析init-param
    ↓
FrameworkServlet.initServletBean()
    ↓
initWebApplicationContext()
    ├─ 获取根容器
    ├─ 创建子容器
    ├─ 设置父子关系
    └─ configureAndRefreshWebApplicationContext()
            ↓
        onRefresh(wac)
            ↓
        initStrategies() - 初始化九大组件

父容器管理Service等业务组件,子容器管理Controller等Web组件,子容器可继承父容器Bean。

要点总结

  1. ContextLoaderListener创建根WebApplicationContext
  2. DispatcherServlet创建子WebApplicationContext,设置父容器
  3. 子容器可访问父容器Bean,实现分层架构
  4. Spring Boot自动配置DispatcherServlet和内嵌容器
  5. 支持多个DispatcherServlet配置不同URL映射

jwdev/articles/SPRINGMVC/专家/容器级WEB组件扩展/容器级WEB组件扩展/SpringMVC容器初始化与DispatcherServlet.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 HandlerMapping与HandlerAdapter扩展
下一篇 → 异常处理HandlerExceptionResolver
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库