BeanFactory vs ApplicationContext: When to Choose Each in Spring
Spring provides two IoC containers—BeanFactory and ApplicationContext—each with distinct loading strategies, features, and registration behaviors; this article demonstrates their differences through practical code examples, highlighting lazy versus eager loading, automatic post‑processor registration, and why ApplicationContext is generally preferred for enterprise applications.
1. Introduction
Spring framework includes two IoC containers – BeanFactory and ApplicationContext . BeanFactory is the most basic version, while ApplicationContext extends its functionality. This article uses concrete examples to illustrate the significant differences between the two containers.
2. Lazy Loading vs. Preloading
BeanFactory loads beans on demand, whereas ApplicationContext loads all beans at startup. Consequently, BeanFactory is lightweight compared to ApplicationContext. Let’s understand this with an example.
2.1 BeanFactory Lazy Loading
Assume we have a singleton bean named Student :
public class Student {
public static boolean isBeanInstantiated = false;
public void postConstruct() {
setBeanInstantiated(true);
}
// standard setters and getters
}We define the postConstruct() method as the init‑method in the BeanFactory configuration file ioc-container-difference-example.xml :
<bean id="student" class="com.baeldung.ioccontainer.bean.Student" init-method="postConstruct"/>Now we write a test case that creates a BeanFactory and checks whether the Student bean is loaded:
@Test
public void whenBFInitialized_thenStudentNotInitialized() {
Resource res = new ClassPathResource("ioc-container-difference-example.xml");
BeanFactory factory = new XmlBeanFactory(res);
assertFalse(Student.isBeanInstantiated());
}Here, the Student object is not initialized . In other words, only the BeanFactory itself is initialized. The bean is created only when we explicitly call getBean() :
@Test
public void whenBFInitialized_thenStudentInitialized() {
Resource res = new ClassPathResource("ioc-container-difference-example.xml");
BeanFactory factory = new XmlBeanFactory(res);
Student student = (Student) factory.getBean("student");
assertTrue(Student.isBeanInstantiated());
}Now the Student bean is successfully loaded, demonstrating that BeanFactory loads beans only when needed.
2.2 ApplicationContext Preloading
Replacing BeanFactory with ApplicationContext triggers eager loading of all beans at startup:
@Test
public void whenAppContInitialized_thenStudentInitialized() {
ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
assertTrue(Student.isBeanInstantiated());
}Even without calling getBean() , the Student object is created. ApplicationContext is considered a heavyweight IoC container because its preloading strategy loads all beans during startup. BeanFactory remains lightweight and is convenient for memory‑constrained systems, but most use cases prefer ApplicationContext.
3. Enterprise Application Features
ApplicationContext enhances BeanFactory with a more framework‑oriented style and provides features useful for enterprise applications, such as internationalization (i18n), event publishing, annotation‑based dependency injection, and simple integration with Spring AOP.
Moreover, ApplicationContext supports virtually all bean scopes, whereas BeanFactory only supports singleton and prototype scopes. Therefore, for complex enterprise applications, ApplicationContext is the better choice.
4. Automatic Registration of BeanFactoryPostProcessor and BeanPostProcessor
ApplicationContext automatically registers BeanFactoryPostProcessor and BeanPostProcessor at startup. BeanFactory does not.
4.1 Registering in BeanFactory
We create two classes: CustomBeanFactoryPostProcessor implementing BeanFactoryPostProcessor , and CustomBeanPostProcessor implementing BeanPostProcessor :
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static boolean isBeanFactoryPostProcessorRegistered = false;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
setBeanFactoryPostProcessorRegistered(true);
}
} public class CustomBeanPostProcessor implements BeanPostProcessor {
private static boolean isBeanPostProcessorRegistered = false;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
setBeanPostProcessorRegistered(true);
return bean;
}
}Both classes are declared in ioc-container-difference-example.xml :
<bean id="customBeanPostProcessor" class="com.baeldung.ioccontainer.bean.CustomBeanPostProcessor"/>
<bean id="customBeanFactoryPostProcessor" class="com.baeldung.ioccontainer.bean.CustomBeanFactoryPostProcessor"/>A test verifies that BeanFactory does not automatically register them:
@Test
public void whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically() {
Resource res = new ClassPathResource("ioc-container-difference-example.xml");
ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);
assertFalse(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
assertFalse(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}We can manually register them:
@Test
public void whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue() {
Resource res = new ClassPathResource("ioc-container-difference-example.xml");
ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);
CustomBeanFactoryPostProcessor bfpp = new CustomBeanFactoryPostProcessor();
bfpp.postProcessBeanFactory(factory);
assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
CustomBeanPostProcessor bpp = new CustomBeanPostProcessor();
factory.addBeanPostProcessor(bpp);
Student student = (Student) factory.getBean("student");
assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}4.2 Registering in ApplicationContext
ApplicationContext automatically registers both processors without extra code. A test confirms this behavior:
@Test
public void whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically() {
ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}Thus, automatic registration works, and using ApplicationContext is recommended because Spring 2.0 and later heavily rely on BeanPostProcessor. Note that with a plain BeanFactory, features such as transactions and AOP will not work unless additional code is written.
5. Conclusion
ApplicationContext offers advanced, enterprise‑oriented capabilities, while BeanFactory provides only basic functionality. Generally, ApplicationContext should be used, reserving BeanFactory for scenarios where memory consumption is extremely critical.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
