Explain the WebApplicationContext hierarchy in a DispatcherServlet setup: root context vs. servlet context.
answer
- Root (ContextLoaderListener) = services/repos
- Servlet (per DispatcherServlet) = controllers/MVC
- Child sees parent, not vice versa
- Duplicate @ComponentScan = duplicate beans
- Boot = single context, no split
basics
~20 sClassic Spring MVC has two contexts: a root WebApplicationContext (services, repositories, shared beans) loaded by ContextLoaderListener, and a child servlet context per DispatcherServlet (controllers, MVC beans). The child sees the parent's beans, not vice versa.
solid answer
~50 sIn a traditional Spring MVC app there are two `WebApplicationContext`s forming a parent-child hierarchy. The **root** context is created by `ContextLoaderListener` and holds shared infrastructure — services, repositories, data sources, security beans. Each **DispatcherServlet** creates its own **child** (servlet) context holding web-layer beans — controllers, `HandlerMapping`s, `ViewResolver`s. The child can **see and inject** parent beans; the parent cannot see child beans. This isolates web concerns and lets multiple DispatcherServlets share one root while having distinct web configs. It also explains a classic bug: an aspect/transaction advice declared only in the child context won't apply to root-context services, and duplicate component scans across both contexts create two bean instances. In **Spring Boot**, there is normally a **single** context (no separate root/servlet split) and the DispatcherServlet uses it directly — the hierarchy is mostly legacy XML/`AbstractAnnotationConfigDispatcherServletInitializer` knowledge.
code
java · 25 lines// Classic two-context setup, no web.xml
public class AppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override // -> ROOT context: services, repos, security, datasource
protected Class<?>[] getRootConfigClasses() {
return new Class[]{ RootConfig.class };
}
@Override // -> SERVLET (child) context: controllers, view resolvers
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ WebMvcConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[]{ "/" };
}
}
// Avoid the duplicate-bean trap:
// RootConfig: @ComponentScan(basePackages="com.app",
// excludeFilters=@Filter(Controller.class))
// WebMvcConfig: @ComponentScan(basePackages="com.app.web",
// includeFilters=@Filter(Controller.class), useDefaultFilters=false)go deeper
Know there can be a shared context of services and a web context of controllers.
Explain parent (root) vs child (servlet) and the child-sees-parent visibility rule.
Discuss duplicate-scan and AOP/transaction scoping pitfalls and why security lives in root.
Contrast the legacy two-context model with Boot's single context and reason about when a hierarchy is still warranted.
## Two-context model (classic Spring MVC) A servlet web app can host multiple Spring `ApplicationContext`s arranged as a hierarchy: ### Root WebApplicationContext - Created by a `ContextLoaderListener` (registered in `web.xml` or via `AbstractAnnotationConfigDispatcherServletInitializer.getRootConfigClasses()`). - Holds **shared, non-web** beans: `@Service`, `@Repository`, `DataSource`, transaction managers, Spring Security, messaging. - Stored in the `ServletContext` under `WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE`. - There is exactly **one** root per web app. ### Servlet (child) WebApplicationContext - Created by **each** `DispatcherServlet` (from `getServletConfigClasses()` / the servlet's `contextConfigLocation`). - Holds **web-layer** beans: `@Controller`, `HandlerMapping`, `HandlerAdapter`, `ViewResolver`, `LocaleResolver`, interceptors. - Its **parent** is set to the root context. ### Visibility rule (crucial) Bean resolution walks **upward**: a child-context bean can `@Autowired` a parent-context bean. The reverse is **not** true — a root bean cannot see servlet-context beans. This is by design: web beans depend on services, not vice versa. ## Why two contexts? - **Reuse**: multiple DispatcherServlets (e.g. `/api/*` and `/reports/*`) can share the same root services while each has its own controllers/view config. - **Separation of concerns**: infrastructure lifecycle is independent of any single servlet. - **Lifecycle**: the root is available to servlet **filters** (e.g. Spring Security's `DelegatingFilterProxy` looks up beans in the root context) that run **before** the DispatcherServlet. ## Classic gotchas - **Duplicate component scanning**: if both root config and servlet config `@ComponentScan` the same packages, you get **two** instances of some beans — one per context. Rule of thumb: scan controllers only in the servlet context, everything else in root. - **AOP/transaction scope**: `@EnableTransactionManagement` or an `@Aspect` declared in one context only advises beans in **that** context. Declaring transactions in the servlet context won't wrap root-context services. - **Security beans**: Spring Security is typically in the root context because filters (outside the DispatcherServlet) need it. ## Spring Boot reality Spring Boot's default is a **single** `ApplicationContext` — there is generally no separate root/servlet split; `DispatcherServletAutoConfiguration` wires the DispatcherServlet to use the one Boot context. So the duplicate-scan and cross-context AOP problems mostly vanish. The hierarchy still matters when: you run multiple DispatcherServlets, use `spring-boot`'s hierarchical `SpringApplicationBuilder.child(...)`, or maintain legacy XML apps. Interviewers ask this to check you understand *why* the split existed and can debug the resulting bean-visibility surprises. ## Accessing the context - Root: `WebApplicationContextUtils.getWebApplicationContext(servletContext)`. - Servlet: stored under `FrameworkServlet.SERVLET_CONTEXT_PREFIX + servletName`.
- Can a @Service in the root context inject a @Controller from the servlet context?No. Visibility only goes child→parent, so services (root) cannot see controllers (child). Controllers can inject services, not the other way around.
- Why is Spring Security usually configured in the root context?Its filter chain (via DelegatingFilterProxy) runs before the DispatcherServlet as a servlet filter, so the beans it needs must live in the root context that filters can reach.
- Does Spring Boot use this two-context hierarchy by default?No — Boot uses a single application context by default and points the DispatcherServlet at it, so the root/servlet split (and its duplicate-scan pitfalls) generally doesn't apply.
saying these in an interview costs you the question
- Saying the parent context can access child (servlet) beans
- Claiming Spring Boot always has separate root and servlet contexts
- Not knowing duplicate component scans create duplicate beans
- Thinking transactions declared in the servlet context wrap root services