Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

November Discount Launch 2022 – Top
We’re finally running a Black Friday launch. All Courses are 30% off until next Friday:

>> GET ACCESS NOW

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

NPI – Lightrun – Spring (partner)

We rely on other people’s code in our own work. Every day. It might be the language you’re writing in, the framework you’re building on, or some esoteric piece of software that does one thing so well you never found the need to implement it yourself.

The problem is, of course, when things fall apart in production - debugging the implementation of a 3rd party library you have no intimate knowledge of is, to say the least, tricky. It’s difficult to understand what talks to what and, specifically, which part of the underlying library is at fault.

Lightrun is a new kind of debugger.

It's one geared specifically towards real-life production environments. Using Lightrun, you can drill down into running applications, including 3rd party dependencies, with real-time logs, snapshots, and metrics. No hotfixes, redeployments, or restarts required.

Learn more in this quick, 5-minute Lightrun tutorial:

>> The Essential List of Spring Boot Annotations and Their Use Cases

1. Overview

The Spring Framework comes with two IOC containers – BeanFactory and ApplicationContext. The BeanFactory is the most basic version of IOC containers, and the ApplicationContext extends the features of BeanFactory.

In this quick tutorial, we'll understand the significant differences between these two IOC containers with practical examples.

2. Lazy Loading vs. Eager Loading

BeanFactory loads beans on-demand, while ApplicationContext loads all beans at startup. Thus, BeanFactory is lightweight as compared to ApplicationContext. Let's understand it with an example.

2.1. Lazy Loading With BeanFactory

Let's suppose we have a singleton bean class called Student with one method:

public class Student {
    public static boolean isBeanInstantiated = false;

    public void postConstruct() {
        setBeanInstantiated(true);
    }

    //standard setters and getters
}

We'll define the postConstruct() method as the init-method in our BeanFactory configuration file, ioc-container-difference-example.xml:

<bean id="student" class="com.baeldung.ioccontainer.bean.Student" init-method="postConstruct"/>

Now, let's write a test case that creates a BeanFactory to check if it loads the Student bean:

@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 is initialized. The beans defined in our BeanFactory will be loaded only when we explicitly call the getBean() method.

Let's check the initialization of our Student bean where we're manually calling the getBean() method:

@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());
}

Here, the Student bean loads successfully. Hence, the BeanFactory only loads the bean when it is required.

2.2. Eager Loading With ApplicationContext

Now, let's use ApplicationContext in the place of BeanFactory.

We'll only define ApplicationContext, and it will load all the beans instantly by using an eager-loading strategy:

@Test
public void whenAppContInitialized_thenStudentInitialized() {
    ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
    
    assertTrue(Student.isBeanInstantiated());
}

Here, the Student object is created even though we have not called the getBean() method.

ApplicationContext is considered a heavy IOC container because its eager-loading strategy loads all the beans at startup. BeanFactory is lightweight by comparison and could be handy in memory-constrained systems. Nevertheless, we'll see in the next sections why ApplicationContext is preferred for most use cases.

3. Enterprise Application Features

ApplicationContext enhances BeanFactory in a more framework-oriented style and provides several features that are suitable for enterprise applications.

For instance, it provides messaging (i18n or internationalization) functionality, event publication functionality, annotation-based dependency injection, and easy integration with Spring AOP features.

Apart from this, the ApplicationContext supports almost all types of bean scopes, but the BeanFactory only supports two scopes — Singleton and Prototype. Therefore, it's always preferable to use ApplicationContext when building complex enterprise applications.

4. Automatic Registration of BeanFactoryPostProcessor and BeanPostProcessor

The ApplicationContext automatically registers BeanFactoryPostProcessor and BeanPostProcessor at startup. On the other hand, the BeanFactory does not register these interfaces automatically.

4.1. Registration in BeanFactory

To understand, let's write two classes.

Firstly, we have the CustomBeanFactoryPostProcessor class, which implements the BeanFactoryPostProcessor:

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    private static boolean isBeanFactoryPostProcessorRegistered = false;
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
        setBeanFactoryPostProcessorRegistered(true);
    }

    // standard setters and getters
}

Here, we've overridden the postProcessBeanFactory() method to check its registration.

Secondly, we have another class, CustomBeanPostProcessor, which implements BeanPostProcessor:

public class CustomBeanPostProcessor implements BeanPostProcessor {
    private static boolean isBeanPostProcessorRegistered = false;
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName){
        setBeanPostProcessorRegistered(true);
        return bean;
    }

    //standard setters and getters
}

Here, we've overridden the postProcessBeforeInitialization() method to check its registration.

Also, we've configured both the classes in our ioc-container-difference-example.xml configuration file:

<bean id="customBeanPostProcessor" 
  class="com.baeldung.ioccontainer.bean.CustomBeanPostProcessor" />
<bean id="customBeanFactoryPostProcessor" 
  class="com.baeldung.ioccontainer.bean.CustomBeanFactoryPostProcessor" />

Let's see a test case to check whether these two classes are registered automatically during startup:

@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());
}

As we can see from our test, automatic registration did not happen.

Now, let's see a test case that manually adds them in the BeanFactory:

@Test
public void whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue() {
    Resource res = new ClassPathResource("ioc-container-difference-example.xml");
    ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);

    CustomBeanFactoryPostProcessor beanFactoryPostProcessor 
      = new CustomBeanFactoryPostProcessor();
    beanFactoryPostProcessor.postProcessBeanFactory(factory);
    assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());

    CustomBeanPostProcessor beanPostProcessor = new CustomBeanPostProcessor();
    factory.addBeanPostProcessor(beanPostProcessor);
    Student student = (Student) factory.getBean("student");
    assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}

Here, we used the postProcessBeanFactory() method to register CustomBeanFactoryPostProcessor and the addBeanPostProcessor() method to register CustomBeanPostProcessor. Both of them register successfully in this case.

4.2. Registration in ApplicationContext

As we noted earlier, ApplicationContext registers both the classes automatically without writing additional code.

Let's verify this behavior in a unit test:

@Test
public void whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically() {
    ApplicationContext context 
      = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");

    assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
    assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}

As we can see, automatic registration of both classes is successful in this case.

Therefore, it's always advisable to use ApplicationContext because Spring 2.0 (and above) heavily uses BeanPostProcessor.

It's also worth noting that if you're using the plain BeanFactory, then features like transactions and AOP will not take effect (at least not without writing extra lines of code). This may lead to confusion because nothing will look wrong with the configuration.

5. Conclusion

In this article, we've seen the key differences between ApplicationContext and BeanFactory with practical examples.

The ApplicationContext comes with advanced features, including several that are geared towards enterprise applications, while the BeanFactory comes with only basic features. Therefore, it's generally recommended to use the ApplicationContext, and we should use BeanFactory only when memory consumption is critical.

As always, the code for the article is available over on GitHub.

November Discount Launch 2022 – Bottom
We’re finally running a Black Friday launch. All Courses are 30% off until next Friday:

>> GET ACCESS NOW

Generic footer banner
Comments are closed on this article!