Understanding Spring’s Parent and Child Container Initialization in XML Config
This article explains how Spring configures its parent and child application contexts using web.xml, ContextLoaderListener, and DispatcherServlet, detailing the loading of configuration files, context class determination, bean definition processing, and the refresh cycle that ultimately stores the WebApplicationContext in the ServletContext.
Configuration File (web.xml)
<code><web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app></code>Parent Container Initialization (ContextLoaderListener)
<code><listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener></code> <code>public class ContextLoader {
private WebApplicationContext context;
private static final Properties defaultStrategies;
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
static {
try {
String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
} catch (IOException ex) {
throw new IllegalStateException("Could not load 'ContextLoader.properties'", ex);
}
}
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
Class<?> contextClass = determineContextClass(sc);
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
protected Class<?> determineContextClass(ServletContext servletContext) {
String contextClassName = servletContext.getInitParameter("contextClass");
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
} catch (ClassNotFoundException ex) {
throw new IllegalStateException("Failed to load context class [" + contextClassName + "]", ex);
}
} else {
String className = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(className, ContextLoader.class.getClassLoader());
} catch (ClassNotFoundException ex) {
throw new IllegalStateException("Failed to load default context class [" + className + "]", ex);
}
}
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
wac.setServletContext(sc);
String configLocation = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
wac.refresh();
}
}
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
return this.context;
}
}
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
return new String[] {DEFAULT_CONFIG_LOCATION};
}
@Override
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String location : configLocations) {
reader.loadBeanDefinitions(location);
}
}
}
}
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
@Override
public void refresh() {
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// further refresh steps omitted for brevity
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
}
</code>Summary of Parent Container Initialization
Spring reads the contextClass parameter from the configuration file; if absent, it falls back to ContextLoader.properties inside the Spring JAR to determine the concrete ApplicationContext implementation.
The determined ApplicationContext (typically XmlWebApplicationContext ) is instantiated, its configuration location is set (default /WEB-INF/applicationContext.xml if not overridden), and the context is refreshed.
The refreshed context is stored in the ServletContext under the attribute name WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE .
Child Container Initialization (DispatcherServlet)
<code>public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
public final void init() throws ServletException {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
initServletBean();
}
}
</code> <code>public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
private String contextConfigLocation;
@Override
protected final void initServletBean() throws ServletException {
this.webApplicationContext = initWebApplicationContext();
}
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
wac = createWebApplicationContext(rootContext);
}
return wac;
}
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = getContextClass();
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
configureAndRefreshWebApplicationContext(wac);
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.refresh();
}
public String getNamespace() {
return (this.namespace != null ? this.namespace : getServletName() + DEFAULT_NAMESPACE_SUFFIX);
}
public String getContextConfigLocation() {
return this.contextConfigLocation;
}
}
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
</code>Summary of Child Container Initialization
DispatcherServlet reads its contextConfigLocation init‑param (or defaults) via a BeanWrapper and sets it on the underlying FrameworkServlet .
The servlet creates a child WebApplicationContext (default XmlWebApplicationContext ), optionally inheriting the parent context created by ContextLoaderListener .
The child context’s namespace is derived from the servlet name (e.g., app-servlet ), its configuration file is resolved (default /WEB-INF/app-servlet.xml ), and the context is refreshed, completing the Spring MVC setup.
Finished!
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.