ApplicationContext
BeanFactory vs ApplicationContext, XML config, Java config, annotation-based config
ApplicationContext
1. Definition
ApplicationContext is the central interface of the Spring Framework that provides full IoC container functionality. It extends BeanFactory but goes far beyond it by offering integrated AOP support, internationalization (i18n), event handling, and environment abstraction. Most Spring applications use ApplicationContext instead of BeanFactory because all services needed for production operation are available here.
In Spring Boot applications, ApplicationContext is created automatically by SpringApplication.run() — typically as AnnotationConfigServletWebServerApplicationContext for web applications.
2. Core Concepts
BeanFactory vs ApplicationContext
| Feature | BeanFactory | ApplicationContext |
|---|---|---|
| Bean creation | Lazy (on first lookup) | Eager (singletons at startup) |
| Event handling | ❌ | ✅ ApplicationEventPublisher |
| i18n (MessageSource) | ❌ | ✅ |
| AOP integration | Manual | Automatic |
| BeanPostProcessor registration | Manual | Automatic |
| Environment / Profile | ❌ | ✅ |
| ResourceLoader | Basic | Advanced (classpath, file, URL) |
BeanFactory is a lightweight container that only handles bean instantiation and DI. ApplicationContext contains everything BeanFactory does, plus enterprise-level services.
Main ApplicationContext Implementations
AnnotationConfigApplicationContext— Java config (@Configurationclasses) in standalone applicationsClassPathXmlApplicationContext— XML configuration from classpathGenericWebApplicationContext— Web environment, servlet container integrationAnnotationConfigServletWebServerApplicationContext— Spring Boot web application (default)
Configuration Styles
XML-based — The classic approach, <beans> root element, <bean> definitions:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="...">
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="jdbc:h2:mem:test"/>
</bean>
</beans>
Java config — @Configuration + @Bean:
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:h2:mem:test");
return ds;
}
}
Annotation-based — @ComponentScan + stereotype annotations (@Component, @Service, @Repository):
@Configuration
@ComponentScan("com.example")
public class AppConfig {}
In practice most Spring Boot projects use a combination of Java config and annotation-based approaches. XML config appears in legacy code.
3. Practical Usage
Starting Context in a Standalone Application
// Java config
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = ctx.getBean(UserService.class);
// XML config (legacy)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Spring Boot Application
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(MyApp.class, args);
// ctx is automatically available, rarely need to manually get beans
}
}
Environment and Profiles
@Configuration
@Profile("production")
public class ProdConfig {
@Bean
public DataSource dataSource() {
// production DataSource
}
}
Activation: spring.profiles.active=production (application.properties or JVM arg).
Event Handling
// Publishing an event
@Service
public class OrderService {
private final ApplicationEventPublisher publisher;
public OrderService(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void placeOrder(Order order) {
// business logic
publisher.publishEvent(new OrderPlacedEvent(order));
}
}
// Listening for events
@Component
public class NotificationListener {
@EventListener
public void onOrderPlaced(OrderPlacedEvent event) {
// send notification
}
}
i18n (MessageSource)
@Autowired
private MessageSource messageSource;
String msg = messageSource.getMessage("greeting", null, Locale.forLanguageTag("hu"));
4. Code Examples
Full Java Config Application
@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:app.properties")
public class AppConfig {
@Value("${app.name}")
private String appName;
@Bean
public AppInfo appInfo() {
return new AppInfo(appName);
}
}
Combining Multiple Configs
@Configuration
@Import({DataConfig.class, SecurityConfig.class})
public class RootConfig {}
Context Hierarchy (Parent-Child)
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(SharedConfig.class);
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
child.setParent(parent);
child.register(WebConfig.class);
child.refresh();
// child context can access parent beans, but not vice versa
ResourceLoader Usage
@Service
public class TemplateService {
private final ResourceLoader resourceLoader;
public TemplateService(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public String loadTemplate(String path) throws IOException {
Resource resource = resourceLoader.getResource("classpath:" + path);
return new String(resource.getInputStream().readAllBytes());
}
}
5. Trade-offs
| Aspect | Advantage | Disadvantage |
|---|---|---|
| Eager initialization (singleton) | Errors surface at startup (fail-fast) | Slower startup with many beans |
| Java config vs XML | Type-safe, IDE refactoring | More complex @Conditional logic |
| XML config | Declarative, can change without code | Verbose, no compiler checks |
| Annotation-based config | Minimal boilerplate | Scattered configuration, hard to review |
| @ComponentScan | Automatic, less code | Not obvious what enters the context |
| Explicit @Bean | Full control, documented | More code, maintenance |
When to Use Which Approach?
- New project: Java config + annotations (Spring Boot default)
- External library bean:
@Beanmethod in@Configurationclass - Legacy integration:
@ImportResource("legacy-context.xml") - Conditional bean:
@Conditional*annotations in Java config
6. Common Mistakes
❌ Not Closing Context (Standalone App)
// BAD — resource leak
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// usage...
// @PreDestroy callbacks never execute
// GOOD — try-with-resources
try (var ctx = new AnnotationConfigApplicationContext(AppConfig.class)) {
ctx.getBean(MyService.class).doWork();
} // @PreDestroy called automatically
❌ Using BeanFactory Instead of ApplicationContext
// BAD — no AOP, no Events, no auto-registered BeanPostProcessors
BeanFactory factory = new DefaultListableBeanFactory();
// GOOD — use ApplicationContext
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
❌ Calling Context refresh() Multiple Times
// BAD — duplicate beans, memory leak
ctx.refresh();
ctx.refresh();
❌ Wrong Profile Activation Order
// BAD — profile must be set before context refresh
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.refresh();
ctx.getEnvironment().setActiveProfiles("prod"); // No effect!
// GOOD
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("prod");
ctx.register(AppConfig.class);
ctx.refresh();
7. Deep Dive
Context Lifecycle
- Bean definition loading — parsing
@Configurationclasses, XML files - BeanFactoryPostProcessor execution — modifying bean definitions (e.g.,
PropertySourcesPlaceholderConfigurer) - Bean instantiation — eager creation of singleton beans
- BeanPostProcessor execution — AOP proxy, @Autowired resolution
- Context ready —
ContextRefreshedEventpublished - Operation — beans in use
- Context close —
ContextClosedEvent, @PreDestroy callbacks
BeanFactoryPostProcessor vs BeanPostProcessor
| Aspect | BeanFactoryPostProcessor | BeanPostProcessor |
|---|---|---|
| When does it run? | After bean definitions loaded, before instantiation | After each bean instantiation |
| What does it modify? | Bean definitions (metadata) | Bean instances |
| Typical usage | Property placeholder resolution, bean definition modification | AOP proxy, @Autowired, @PostConstruct |
Context Hierarchy (Parent-Child)
The classic Spring MVC model: root context (service, repository beans) and servlet context (controllers, view resolvers). The child context can see parent beans, but not vice versa. In Spring Boot this has been simplified — typically a flat context is used.
@Configuration Class CGLIB Proxy
Spring loads @Configuration classes via a CGLIB proxy. This ensures that inter-bean references (one @Bean method calling another) maintain singleton semantics. Setting @Configuration(proxyBeanMethods = false) (lite mode) disables this behavior.
@Configuration
public class AppConfig {
@Bean
public ServiceA serviceA() {
return new ServiceA(commonDep()); // CGLIB: returns singleton
}
@Bean
public ServiceB serviceB() {
return new ServiceB(commonDep()); // CGLIB: returns SAME instance
}
@Bean
public CommonDep commonDep() {
return new CommonDep();
}
}
8. Interview Questions
What is the difference between BeanFactory and ApplicationContext? BeanFactory is the basic DI container (lazy init). ApplicationContext contains everything plus events, i18n, AOP, auto-registered BeanPostProcessors, Environment.
What ApplicationContext implementations do you know?
AnnotationConfigApplicationContext,ClassPathXmlApplicationContext,GenericWebApplicationContext, Spring Boot:AnnotationConfigServletWebServerApplicationContext.What is the difference between Java config and annotation-based config? Java config: explicit
@Beanmethods in@Configurationclasses. Annotation-based:@ComponentScan+ stereotype annotations (@Component,@Service). In practice, they are combined.How does the @Configuration CGLIB proxy work? Spring creates a CGLIB subclass of the
@Configurationclass. This way inter-bean references (one@Beanmethod calling another) always return the instance from the singleton cache.proxyBeanMethods = falsedisables this.What is the context lifecycle order? Bean definition load → BeanFactoryPostProcessor → Singleton instantiation → BeanPostProcessor → ContextRefreshedEvent → Usage → ContextClosedEvent → @PreDestroy.
When would you use XML config in 2024? Legacy integration, third-party framework constraints, or when configuration must be modifiable outside of code. For new projects, Java config is recommended.
What is context hierarchy and what is it for? Parent-child context: child can see parent beans, but not vice versa. In classic Spring MVC — root (service) and servlet (web) contexts. In Spring Boot, a flat context is typical.
9. Glossary
| Term | Meaning |
|---|---|
| BeanFactory | Basic IoC container interface, lazy bean init |
| ApplicationContext | Full-featured container (BeanFactory + enterprise services) |
| @Configuration | Java-based configuration class, with CGLIB proxy |
| @ComponentScan | Automatic bean registration by scanning packages |
| @PropertySource | Loads external property file into Environment |
| @Import | Connects multiple configuration classes together |
| @Profile | Conditional activation of beans/config based on profile |
| MessageSource | i18n interface, resolving localized messages |
| ApplicationEventPublisher | Interface for publishing events |
| BeanFactoryPostProcessor | Modifies bean definitions before instantiation |
| ContextRefreshedEvent | Event fired after full context initialization |
| proxyBeanMethods | @Configuration attribute to toggle CGLIB proxy |
10. Cheatsheet
BeanFactory → Lightweight, lazy init, DI only
ApplicationContext → BeanFactory + AOP + Event + i18n + Environment
Configuration styles:
XML: ClassPathXmlApplicationContext("beans.xml")
Java: AnnotationConfigApplicationContext(AppConfig.class)
Boot: SpringApplication.run(MyApp.class, args)
Context lifecycle:
Def load → BFPP → Instantiate → BPP → @PostConstruct → Ready → Close → @PreDestroy
@Configuration:
CGLIB proxy → inter-bean ref = singleton
proxyBeanMethods=false → lite mode, no proxy
Common implementations:
AnnotationConfigApplicationContext standalone + Java config
ClassPathXmlApplicationContext standalone + XML
AnnotationConfigServletWebServerAC Spring Boot web
Context hierarchy:
child.setParent(parent)
child → parent beans visible
parent → child beans NOT visible
Common mistakes:
✗ Using BeanFactory instead of ApplicationContext
✗ Forgetting to close context (standalone)
✗ Setting profile after refresh()
✗ Calling refresh() multiple times
🎮 Games
10 questions