Loading...

Chapter 7: Spring - IoC Containers

Introduction

In Spring, one of the core concepts is the Inversion of Control (IoC) container. The IoC container is responsible for managing the lifecycle and configuration of application objects. It allows for dependency injection, which helps to decouple the components of the application, making it more maintainable, testable, and flexible.

In this chapter, we will learn about the IoC container in Spring, the two main types of IoC containers, and how to use them.


1. What is IoC?

Inversion of Control (IoC) refers to the reversal of the flow of control in a system. Instead of the programmer controlling the flow of execution, the framework (in this case, Spring) controls the flow and the creation of objects.

In traditional programming, objects are created directly by using new or constructors. With IoC, Spring manages object creation, and these objects are injected where they are needed. This helps in promoting loose coupling between components.


2. Types of IoC Containers in Spring

Spring provides two main types of IoC containers:

  • BeanFactory Container: The simplest container, used for lightweight applications.
  • ApplicationContext Container: A more advanced container with more features, including event propagation, declarative mechanisms, and integration with Spring’s AOP features.
a. BeanFactory Container

The BeanFactory container is the simplest and most lightweight container. It uses the Factory Design Pattern to manage beans. BeanFactory is used when the application has minimal requirements and doesn’t need complex features.

Example:

BeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
MyBean myBean = (MyBean) factory.getBean("myBean");
b. ApplicationContext Container

The ApplicationContext is the more commonly used container and extends BeanFactory. It provides more features, such as event handling, AOP (Aspect-Oriented Programming), and internationalization support. It is more suitable for most Spring applications.

ApplicationContext can be loaded using various types of configuration, such as:

  • XML-based configuration (ClassPathXmlApplicationContext)
  • Annotation-based configuration (AnnotationConfigApplicationContext)

Example:

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
MyBean myBean = (MyBean) context.getBean("myBean");

3. IoC Container Workflow

The workflow of the IoC container can be broken down into the following steps:

  1. Configuration: The IoC container is configured using a configuration file (XML, Java, or annotations) where beans are defined and their dependencies are set.
  2. Instantiation: The container instantiates the beans as per the configuration and manages their lifecycle.
  3. Dependency Injection: The container injects the required dependencies into the beans either via constructor injection, setter injection, or field injection.
  4. Bean Lifecycle Management: The container manages the lifecycle of beans (from initialization to destruction).
  5. Accessing Beans: Beans are retrieved from the container when required by other beans or components.

4. Using ApplicationContext to Create a Spring Bean

In this section, we will demonstrate how to use the ApplicationContext container to load and manage beans.

a. Creating the Bean

Let’s use the HelloWorldService class from the previous example as a Spring bean and manage it using ApplicationContext.

  1. Create the AppConfig.java Configuration Class:
package com.example.springapplication;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public HelloWorldService helloWorldService() {
        return new HelloWorldService();
    }
}

Here, the @Configuration annotation marks this class as a configuration class, and the @Bean annotation tells Spring to treat the helloWorldService() method as a Spring bean.

b. Setting Up the ApplicationContext

Now, in the MainApp.java class, we will load the ApplicationContext and retrieve the bean.

package com.example.springapplication;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        // Initialize Spring IoC container
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // Retrieve the bean from the container
        HelloWorldService helloWorldService = context.getBean(HelloWorldService.class);

        // Call the method on the bean
        helloWorldService.sayHello();

        // Close the context
        context.close();
    }
}

In this example, we are using the AnnotationConfigApplicationContext class to load the configuration (AppConfig.class), which contains the bean definition for HelloWorldService.


5. Bean Lifecycle Management

Spring IoC container is responsible for managing the lifecycle of beans. The lifecycle can be broken into several stages:

  1. Instantiation: The container creates an instance of the bean.
  2. Dependency Injection: Spring injects any required dependencies into the bean.
  3. Post-Processing: The BeanPostProcessor interface can be used to manipulate beans after they are instantiated but before they are used.
  4. Initialization: If the bean implements the InitializingBean interface or has a custom init-method, it will be called after the dependencies are injected.
  5. Destruction: If the bean implements the DisposableBean interface or has a custom destroy-method, it will be called when the container is closed.

Spring provides the @PostConstruct and @PreDestroy annotations to handle bean initialization and destruction in a more declarative way.


6. Bean Scopes in Spring

Spring supports several bean scopes, which determine the lifespan and visibility of the bean within the IoC container. The main scopes are:

  • Singleton (default): Only one instance of the bean is created for the entire Spring container.
  • Prototype: A new instance of the bean is created every time it is requested.
  • Request: A new instance of the bean is created for each HTTP request (used in web applications).
  • Session: A new instance is created for each HTTP session (used in web applications).
  • Global Session: A new instance is created for each global HTTP session (used in portlet-based applications).

Example of defining a bean with a scope:

@Bean
@Scope("prototype")
public HelloWorldService helloWorldService() {
    return new HelloWorldService();
}

Conclusion

In this chapter, we learned about the IoC container in Spring. The IoC container is responsible for managing the lifecycle of beans and providing dependency injection. We also explored the two main types of containers (BeanFactory and ApplicationContext), their configuration, and usage. Additionally, we discussed the bean lifecycle, scopes, and lifecycle management features provided by Spring.

In the next chapter, we will dive deeper into Bean Definitions and explore how Spring manages beans.

Are you ready to continue to the next chapter?