IoC Container – BeanFactory and ApplicationContext

One of the most important parts of the Spring framework is the Spring IoC Container. The container behaves as a factory of beans. We provide the configuration metadata to the container and the container provides us the instances of beans along with their dependencies. The configuration metadata can be provided by XML file or Java annotations, or Java code. The configuration metadata contains how to instantiate beans, where to inject dependencies etc.

XML-Based configuration

Most of the time, we will use annotation based configuration. But to show you how XML based confirmation, first create a few Java classes.

Suppose we have a Vehicle class that depends on the Engine class to start.

public interface Engine {
    void start();
}
public class EngineImpl implements Engine {
    public void start() {
        System.out.println("Starting engine...");
    }
}
public class Vehicle {
    private Engine engine; // dependency

    public void setEngine(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        engine.start();
    }
}

As Vehicle class dependents on an implementation of Engine interface, you have to inform Spring container via configuration that whenever you request a Vehicle instance, container must return that instance along with the engine field populated. In XML based configuration we provide that configuration using <bean> elements.

We will create a file called spring-config.xml under the src/main/resources folder.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="vehicle" class="com.kcs.service.Vehicle">
        <property name="engine"><ref bean="engineBean"/></property>
    </bean>
    <bean id="engineBean" class="com.kcs.impl.EngineImpl" />
</beans>

As you can see, we have declared 2 beans with unique id. Also we have used the ref attribute to assign a bean with id engineBean to the engine property of vehicle bean. Please note, we must have a setter method for the field engine. You can also specify constructor arguments, but let’s not go into detail. We already know how to configure constructor injection using annotation.

Java-based configuration

In the case of Java-based configuration, instead of an XML file, we create a configuration class that is annotated with @Configuration annotation. Inside this class we create methods that are annotated with @Bean annotation. From those methods, we construct and return bean instances. Consider @Bean annotation equivalent to <bean> element. Spring container will use method name as the bean name. When you request a bean, the container will call the appropriate method annotated with @Bean and return the instance.

The equivalent Java configuration of the XML configuration is given below –

@Configuration
public class AppConfig {

    @Bean
    public Engine engineBean() {
        return new EngineImpl();
    }
    
    @Bean
    public Vehicle vehicle() {
        Vehicle vehicle = new Vehicle();
        vehicle.setEngine(engineBean());
        return vehicle;
    }
}

If we want to assign a different name to the bean rather than the method name, we can do that by passing the desired bean name to the @Bean annotation.

@Bean("engine")
public Engine engineBean() {
    return new EngineImpl();
}

We can also mix XML configuration with Java configuration. For example, let’s assume you have kept the Vehicle and Engine bean definition in an XML file and you want to import that configuration in your configuration class. To achieve this, you can use @ImportResource annotation.

@Configuration
@ImportResource(locations = "classpath:Spring-config.xml")
public class AppConfig { 

}
Annotation-Based configuration

In case of annotation-based configuration, we annotate bean classes with the appropriate stereotype annotation like @Component, @Service etc. and use @Autowired annotation on fields, setters and constructors to configure the dependency.

Also, we have to request Spring to scan our application to find the annotated classes. To do that, in our configuration class we can use @ComponentScan annotation and specify the package name. Spring will scan for the annotated classes under the specified package and all of its sub-packages. If we use @ComponentScan without specifying the package name, Spring will scan the current package in which the configuration class is preset and all of its sub-packages.

So, the annotation based configuration will look like below –

@Component
public class EngineImpl implements Engine {
    public void start() {
        System.out.println("Starting engine...");
    }
}
@Service
public class Vehicle {
    @Autowired
    private Engine engine;
   
    public void start() {
        engine.start();
    }
}
@ComponentScan(basePackages = {"com.kcs"})
@Configuration
public class AppConfig {

}

In case of annotation-based configuration, if we don’t specify any name, class names will be used as the name. Only the first letter will be downcasted. So the name of Vehicle bean would be vehicle. We are also allowed to explicitly specify the bean name as shown below.

@Service(“twoWheeler”)
public class Vehicle {
    ......
}
Instantiating a container

As our bean configuration is done, let’s instantiate a container. Spring Framework provides two types of Containers –

  1. Bean Factory
  2. Application Context

Bean Factory : The BeanFactory is the actual container that instantiates, injects dependencies and manages a number of beans. BeanFactory only supports XML based configuration. The most commonly used implementation of BeanFactory is the XmlBeanFactory class.

Application Context : This interface is built on top of the BeanFactory interface to provide additional functionality like internationalization, event publication, AOP service etc. Always try to use ApplicationContext. The commonly used implementations of this interface are: AnnotationConfigApplicationContex, AnnotationConfigWebApplicationContext etc.

To instantiate Spring IoC container using XmlBeanFactory you can do as following –

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("Spring-config.xml"));
Vehicle vehicle = beanFactory.getBean(Vehicle.class);

To instantiate Spring IoC container using AnnotationConfigApplicationContex you can do as following –

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Vehicle vehicle = ctx.getBean(Vehicle.class);
Differences between BeanFactory and ApplicationContext
FeatureBeanFactoryApplicationContext
ImplementationXMLBeanFactoryAnnotationConfigWebApplicationContext, AnnotationConfigApplicationContext etc.
Annotation SupportNoYes
InstantiationBenaFactory instantiates beans when the getBean() method gets called.ApplicationContext instainte bean at the time container starts.
Event PublicationBean factory does not have the ability to push events to the beans.Application Context has the ability to push to push events to the beans.
InternationalizationNoYes

That’s it for now. Hope you have enjoyed this tutorial. If you have any doubt, please ask in the comment section. I will try to answer that as soon as possible. Till then, bye bye.

One thought on “IoC Container – BeanFactory and ApplicationContext

  1. Itís nearly impossible to find experienced people on this subject, but you sound like you know what youíre talking about! Thanks

Comments are closed.