riven

Riven

Riven

What is  IoC Container in spring?

The Spring IoC container is responsible for managing the complete lifecycle of application objects, known as beans. The container uses DI to inject dependencies into beans, allowing for more modular, testable, and maintainable code. By managing beans’ lifecycle and dependencies, the Spring container promotes loose coupling and adherence to the Single Responsibility Principle.

Key Concepts of Spring IoC Container

  1. Beans: Objects that form the backbone of a Spring application. They are managed by the Spring container.
  2. Dependency Injection: The process of providing an external dependency to a class rather than the class creating it itself. This can be done through constructor injection, setter injection, or method injection.
  3. Configuration Metadata: Information that the Spring container uses to configure beans. This can be in the form of XML files, annotations, or Java configuration classes.
  4. Scope: Defines the lifecycle of a bean. The common scopes are:
    • Singleton: One instance per Spring IoC container (default).
    • Prototype: A new instance for every request.
    • Request: A new instance for each HTTP request (web applications).
    • Session: A new instance for each HTTP session (web applications).
    • Global Session: A new instance for each global HTTP session (rarely used).

Types of Spring Containers

There are two main types of Spring containers:

  1. BeanFactory: The simplest container, providing basic support for DI and is suitable for lightweight applications.
  2. ApplicationContext: A more advanced container that builds on BeanFactory’s capabilities. It includes features like event propagation, internationalization, and the ability to load multiple configuration files.

Spring Container Architecture

The architecture of the Spring container can be divided into several key components:

  1. BeanDefinition: Contains the metadata about a bean, including its properties, constructor arguments, and scope.
  2. BeanFactory: Interface that defines methods for retrieving beans.
  3. ApplicationContext: Interface that extends BeanFactory, adding more enterprise-specific functionality.
  4. BeanPostProcessor: Interface that allows custom modification of new bean instances before and after their initialization.
  5. Lifecycle Interfaces: Provide methods to manage the lifecycle of beans, such as InitializingBean, DisposableBean, and custom init/destroy methods.

Dependency Injection Types

1. Constructor Injection

In constructor injection, the required dependencies are provided through a class constructor.

				
					public class Car {
    private Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }
}
				
			

2. Setter Injection

In setter injection, dependencies are provided through setter methods.

				
					console.log( 'Code is Poetry' );
				
			

Configuration Metadata

The Spring IoC container can be configured using:

  1. XML Configuration: Defining beans and their dependencies in an XML file.
  2. Annotation-based Configuration: Using annotations to define beans and their relationships.
  3. Java-based Configuration: Using Java classes annotated with @Configuration to define beans.

Example: Building a Simple Spring Application

Let’s create a simple Spring application that demonstrates the IoC container, dependency injection, and various configuration methods. We’ll build a small application to simulate a car rental service.

Step 1: Setting Up the Project

You can set up a Spring project using Maven or Gradle. Here’s a sample pom.xml for Maven:

				
					<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>spring-car-rental</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.10</version>
        </dependency>
    </dependencies>
</project>
				
			

Step 2: Defining the Beans

Create the following classes: Engine, Car, and RentalService.

				
					// Engine.java
public class Engine {
    private String type;

    public Engine(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }
}

// Car.java
public class Car {
    private Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        System.out.println("Car with " + engine.getType() + " engine started.");
    }
}

// RentalService.java
public class RentalService {
    private Car car;

    public RentalService(Car car) {
        this.car = car;
    }

    public void rentCar() {
        System.out.println("Renting out the car.");
        car.start();
    }
}
				
			

Step 3: XML Configuration

Create an XML configuration file beans.xml:

				
					<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.xsd">

    <bean id="engine" class="com.example.Engine">
        <constructor-arg value="V8"/>
    </bean>

    <bean id="car" class="com.example.Car">
        <constructor-arg ref="engine"/>
    </bean>

    <bean id="rentalService" class="com.example.RentalService">
        <constructor-arg ref="car"/>
    </bean>
</beans>
				
			

Step 4: Application Context

Create a main application class to load the Spring context and execute the service:

				
					import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CarRentalApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        RentalService rentalService = context.getBean(RentalService.class);
        rentalService.rentCar();
    }
}
				
			

Step 5: Running the Application

When you run the CarRentalApp, you should see the output:

				
					Renting out the car.
Car with V8 engine started.
				
			

Annotation-based Configuration

Instead of using XML, we can configure our beans using annotations. Let’s modify our classes to use annotations:

				
					import org.springframework.stereotype.Component;

@Component
public class Engine {
    private String type = "V8";

    public String getType() {
        return type;
    }
}

@Component
public class Car {
    private final Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        System.out.println("Car with " + engine.getType() + " engine started.");
    }
}

@Component
public class RentalService {
    private final Car car;

    public RentalService(Car car) {
        this.car = car;
    }

    public void rentCar() {
        System.out.println("Renting out the car.");
        car.start();
    }
}
				
			

Now, we need a configuration class to enable component scanning:

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

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
				
			

And modify the CarRentalApp class:

				
					import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class CarRentalApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        RentalService rentalService = context.getBean(RentalService.class);
        rentalService.rentCar();
    }
}
				
			

When you run the application again, you’ll get the same output using annotation-based configuration.

Related topic

java primitive data types
Java primitive data types In Java primitive data types are the most basic types of data. Unlike reference...
Java operators with example
Java operators with example Operators are special symbols that perform operations on variables and values....
Java instanceof
Java instanceof In Java instanceof operator is a fundamental part of the language that allows you to...
Java ternary operator
Java ternary operators The java ternary operators is a concise way to perform conditional expressions....
Java Unary Operators
Java unary operators Unary operators in Java are some of the simplest yet most powerful tools available...
if statement java
Java if statement The if statement is used to execute a block of code conditionally, based on whether...
Switch statement in java
Java switch statement The switch statement in Java is a powerful control flow structure that allows you...
Else if statement
Java else if statement The else if statement in Java is a powerful construct that allows for more complex...
Java for loop with example
Java for loop with example The for loop is one of the most commonly used control flow statements in Java,...
Java while loop with example
Java while loop with example The while loop is a fundamental control structure in Java that allows developers...