skip to content

BeanFactory vs ApplicationContext

BeanFactory is the bare, lazy lookup container; ApplicationContext is the superset that adds eager singletons, BeanPostProcessors, events, i18n and resource loading. A classic opening question, because the answer shows whether you know what Spring Boot actually starts for you.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is the difference between BeanFactory and ApplicationContext in Spring?

level: juniorimportance: must knowfreq 85%

answer

  1. ApplicationContext = BeanFactory superset
  2. Eager singletons vs lazy lookup
  3. BPP auto-detect, events, i18n, resources
  4. DefaultListableBeanFactory is the engine
  5. Fail-fast at startup

basics

~20 s

Both are Spring IoC containers that create and wire beans. ApplicationContext is a superset of BeanFactory: it adds features like event publishing, internationalization, easy resource loading, and automatic BeanPostProcessor handling, and it eagerly creates singletons at startup.

solid answer

~30 s

BeanFactory is the root container interface — it defines core dependency injection: get a bean by name/type, check scope, resolve dependencies. It's lazy by default: a bean is only instantiated when first requested. ApplicationContext extends BeanFactory and adds an enterprise superset: ApplicationEvent publishing (ApplicationEventPublisher), MessageSource for i18n, ResourceLoader/resource-pattern support, and Environment access. Crucially, ApplicationContext auto-detects and registers BeanPostProcessors and BeanFactoryPostProcessors from bean definitions, and eagerly pre-instantiates all non-lazy singletons at startup so wiring errors surface immediately. In practice you almost always use ApplicationContext (e.g. AnnotationConfigApplicationContext, or the one Spring Boot creates). BeanFactory (DefaultListableBeanFactory) is the underlying engine ApplicationContext delegates to.

code

java · 12 lines
java
// ApplicationContext: eager, full-featured (normal choice)
try (var ctx = new AnnotationConfigApplicationContext(AppConfig.class)) {
    // all non-lazy singletons already instantiated here
    MyService svc = ctx.getBean(MyService.class);
    ctx.publishEvent(new MyEvent(this));          // events available
    ctx.getMessage("greeting", null, Locale.US);  // i18n available
}

// Raw BeanFactory: lazy, minimal — BeanPostProcessors NOT auto-applied
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions("beans.xml");
MyService svc = bf.getBean(MyService.class); // instantiated only now

go deeper

for a junior

State that both are IoC containers and ApplicationContext is a superset with extra features (events, i18n) and eager startup.

for a middle

Add the specific superset features and that ApplicationContext auto-registers BeanPostProcessors while a raw BeanFactory does not, so annotations wouldn't work.

for a senior

Explain the delegation relationship (ApplicationContext owns a DefaultListableBeanFactory), eager pre-instantiation for fail-fast, and name concrete implementations.

for a principal

Discuss lifecycle (refresh phases), when a bare BeanFactory is actually justified, memory/startup trade-offs, and how post-processors drive the whole annotation/AOP model.

## The two container interfaces Spring's Inversion of Control (IoC) container is the object that creates your objects (called **beans**), injects their dependencies, and manages their lifecycle. Spring exposes it through two main interfaces. ### BeanFactory `org.springframework.beans.factory.BeanFactory` is the **root** interface of the container hierarchy. It defines the minimal contract for dependency injection: - `Object getBean(String name)` / `<T> T getBean(Class<T> type)` — look up a bean - `boolean containsBean(String name)` - `boolean isSingleton(String name)` / `isPrototype(String name)` - `Class<?> getType(String name)` By itself, BeanFactory does the essentials: read bean definitions, instantiate, inject, apply scopes. The most-used concrete implementation is **`DefaultListableBeanFactory`** — this is the actual registry that holds `BeanDefinition` objects and performs autowiring. It's the engine inside every ApplicationContext. **Lazy by default:** a plain BeanFactory instantiates a bean only the first time `getBean` is called for it. Nothing is created up front. ### ApplicationContext `org.springframework.context.ApplicationContext` **extends** BeanFactory (transitively — via `ListableBeanFactory` and `HierarchicalBeanFactory`) and layers on enterprise features. It *is* a BeanFactory plus: - **`ApplicationEventPublisher`** — publish and listen for `ApplicationEvent`s (`@EventListener`, `publishEvent`). - **`MessageSource`** — internationalization (i18n) message resolution (`getMessage`). - **`ResourceLoader` / `ResourcePatternResolver`** — load resources with `classpath:`, `file:`, and wildcard patterns (`getResources("classpath*:...")`). - **`EnvironmentCapable`** — access to `Environment` (profiles + properties). - **Automatic infrastructure detection** — it scans bean definitions and automatically registers any `BeanPostProcessor` and `BeanFactoryPostProcessor` beans, and wires up `ApplicationContextAware`/`ApplicationEventPublisherAware` etc. - **Eager singleton pre-instantiation** — on `refresh()` it calls `finishBeanFactoryInitialization`, which pre-instantiates all non-lazy singletons so misconfiguration fails fast at startup, not at first request. ### How they relate at runtime ApplicationContext does **not** reimplement DI. It *owns* a `DefaultListableBeanFactory` internally and delegates `getBean` etc. to it. So ApplicationContext = BeanFactory engine + enterprise services + eager startup. `AbstractApplicationContext.getBeanFactory()` returns that internal DefaultListableBeanFactory. ### Common implementations - **`AnnotationConfigApplicationContext`** — Java `@Configuration` classes. - **`ClassPathXmlApplicationContext`** — XML config. - **`GenericWebApplicationContext` / `AnnotationConfigServletWebServerApplicationContext`** — web/Boot. - Boot's `SpringApplication.run(...)` returns a `ConfigurableApplicationContext`. ### Gotchas - With a **raw BeanFactory**, BeanPostProcessors are *not* auto-applied — you'd have to register them manually via `addBeanPostProcessor`. This means annotations like `@Autowired`, `@PostConstruct`, AOP proxies won't work out of the box, because they're driven by BeanPostProcessors. That's the #1 reason to never use a bare BeanFactory in application code. - Eager instantiation means a broken bean (missing dependency, bad config) throws at container startup. That's a feature: fail fast. - BeanFactory's laziness is different from `@Lazy`. A ApplicationContext is eager overall but you can mark individual beans `@Lazy` to defer them. ### When to use which Use **ApplicationContext** essentially always. Reach for BeanFactory/DefaultListableBeanFactory only in rare low-level scenarios: extremely memory-constrained environments, or when you're building infrastructure/tooling that programmatically registers bean definitions and wants full control over instantiation timing.

  • Name three capabilities ApplicationContext has that a raw BeanFactory does not.
    Automatic BeanPostProcessor/BeanFactoryPostProcessor registration, application event publishing (ApplicationEventPublisher), MessageSource-based i18n, ResourcePatternResolver for classpath wildcard resources, and Environment access. Also eager pre-instantiation of singletons.
  • Does ApplicationContext reimplement dependency injection, or reuse BeanFactory?
    It reuses it. Internally it holds a DefaultListableBeanFactory and delegates bean creation/wiring to it; ApplicationContext just adds enterprise services and eager startup on top.

saying these in an interview costs you the question

  • Saying BeanFactory and ApplicationContext are unrelated or competing containers (ApplicationContext extends BeanFactory).
  • Claiming ApplicationContext is lazy and BeanFactory is eager (it's the reverse for default singleton timing).
  • Thinking @Autowired/@PostConstruct work automatically in a raw BeanFactory (they need BeanPostProcessors, which a raw BeanFactory does not auto-register).

context

open as a page

Explain eager singleton pre-instantiation in ApplicationContext versus lazy lookup in BeanFactory. Why does it matter?

level: middleimportance: must knowfreq 70%

basics

~20 s

A plain BeanFactory creates a bean only when you first ask for it (lazy). An ApplicationContext creates all non-lazy singleton beans up front at startup (eager), so configuration mistakes fail immediately instead of later at runtime.

open as a page

Walk through the getBean overloads on BeanFactory and when you'd use each.

level: middleimportance: should knowfreq 45%

basics

~20 s

getBean can look a bean up by name (getBean("id")), by type (getBean(MyType.class)), by name and type together, or by type plus constructor arguments (getBean(MyType.class, args...)) for prototype beans. Name lookup returns Object; type lookup is type-safe.

open as a page

Why do @Autowired, @PostConstruct, and AOP proxies work in an ApplicationContext but not in a bare BeanFactory? Explain the BeanPostProcessor role.

level: seniorimportance: should knowfreq 40%

basics

~20 s

Those features are implemented by BeanPostProcessors. ApplicationContext automatically detects and registers BeanPostProcessor beans during startup; a raw BeanFactory does not, so annotation injection, lifecycle callbacks, and proxying silently don't happen unless you register the processors yourself.

open as a page

Is there ever a legitimate reason to use a raw BeanFactory / DefaultListableBeanFactory instead of an ApplicationContext? What trade-offs are you making?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

Almost never in application code. A raw DefaultListableBeanFactory makes sense only for low-level tooling, dynamic programmatic bean registration, or extreme resource constraints — accepting that you lose auto post-processing, events, i18n, resource patterns, and eager fail-fast startup.

open as a page