DEV Community

Tapas Pal
Tapas Pal

Posted on

What's the difference IoC and Dependency Injection?

Inversion of Control (IoC) and Dependency Injection (DI) are related concepts, but they are not the same thing.

Question. Is Dependency Injection the same as Inversion of Control?
Answer: No. IoC is a principle, while DI is one way to implement that principle.

1. What is Inversion of Control (IoC)?
Normally, an object creates and manages its own dependencies.
Without IoC

public class OrderService {

    private PaymentService paymentService;

    public OrderService() {
        paymentService = new PaymentService();
    }
    public void placeOrder() {
        paymentService.processPayment();
    }
}
Enter fullscreen mode Exit fullscreen mode

What happens here?
paymentService = new PaymentService();
OrderService is responsible for:

  • Creating the dependency
  • Managing the dependency
  • Using the dependency

The control is inside OrderService
Problem
Suppose tomorrow you want:
CreditCardPaymentService instead of PaymentService
You must modify: OrderService
This creates tight coupling.

IoC Concept

With IoC: Object creation responsibility is moved outside the class.
Instead of: OrderService creates PaymentService
we do:

  • Someone else creates PaymentService
  • Someone else gives it to OrderService

Control is inverted.
That's why it is called: Inversion of Control

Real-Life Example

Imagine a restaurant.
Without IoC - You go into the kitchen and cook your own food.

Customer --> Kitchen --> Cooks food
Enter fullscreen mode Exit fullscreen mode

Customer controls everything.
With IoC - You sit at the table.

Waiter brings food.

Customer <-- Waiter <-- Kitchen
Enter fullscreen mode Exit fullscreen mode

Customer doesn't control food preparation.
Control has been inverted.

2. What is Dependency Injection (DI)?

Dependency Injection is a technique used to achieve IoC.
Instead of creating dependencies yourself:

new PaymentService()
Enter fullscreen mode Exit fullscreen mode

someone injects them.
Example

public class OrderService {

    private PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
    public void placeOrder() {
        paymentService.processPayment();
    }
}
Enter fullscreen mode Exit fullscreen mode

Now:

OrderService orderService =
        new OrderService(new PaymentService());
Enter fullscreen mode Exit fullscreen mode

Dependency is injected from outside.
This is Dependency Injection.

IoC vs DI

Spring Boot Example
Let's see what Spring does internally.
Step 1: Component

@Service
public class PaymentService {

    public void processPayment() {
        System.out.println("Payment Processed");
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Dependent Class

@Service
public class OrderService {

    private final PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
    public void placeOrder() {
        paymentService.processPayment();
    }
}
Enter fullscreen mode Exit fullscreen mode

Notice: new PaymentService()
does not exist.

Step 3: Spring Starts
When application starts:

@SpringBootApplication
public class Application {
}
Enter fullscreen mode Exit fullscreen mode

Spring scans:

@Service
@Component
@Repository
@Controller
Enter fullscreen mode Exit fullscreen mode

classes. Spring finds:
PaymentService
OrderService

Step 4: Spring Creates Beans
Internally:

PaymentService paymentService =
        new PaymentService();
Enter fullscreen mode Exit fullscreen mode

Bean created.

Stored in IoC Container.

Spring Container
      |
      +--> PaymentService Bean
Enter fullscreen mode Exit fullscreen mode

Step 5: Spring Finds Dependency

Spring sees:

public OrderService(PaymentService paymentService)
Enter fullscreen mode Exit fullscreen mode

It understands: OrderService needs PaymentService

Step 6: Spring Injects Dependency

Internally:

OrderService orderService =
        new OrderService(paymentService);
Enter fullscreen mode Exit fullscreen mode

Spring passes the object.

This is Dependency Injection.

Internal Flow Diagram

Application Starts
       |
       V
Component Scan
       |
       V
Find PaymentService
       |
       V
Create PaymentService Bean
       |
       V
Find OrderService
       |
       V
OrderService requires PaymentService
       |
       V
Inject PaymentService Bean
       |
       V
Create OrderService Bean
       |
       V
Store in IoC Container
Enter fullscreen mode Exit fullscreen mode

What is the IoC Container?

Spring's IoC Container is essentially a registry that manages objects (beans).

Simplified view:

ApplicationContext
       |
       +--> PaymentService
       |
       +--> OrderService
       |
       +--> UserService

Enter fullscreen mode Exit fullscreen mode

The container:

  • Creates objects
  • Injects dependencies
  • Manages lifecycle
  • Destroys objects Types of Dependency Injection

1. Constructor Injection (Recommended)

public OrderService(PaymentService paymentService) {
    this.paymentService = paymentService;
}
Enter fullscreen mode Exit fullscreen mode

Advantages:

  • Immutable dependencies
  • Easy testing
  • Spring recommendation

2. Setter Injection

@Service
public class OrderService {

    private PaymentService paymentService;

    @Autowired
    public void setPaymentService(
            PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Field Injection
@Autowired
private PaymentService paymentService;

Works, but generally discouraged because it makes testing harder.

Inversion of Control (IoC) is a design principle where the control of creating and managing objects is transferred from application code to a container or framework.

Dependency Injection (DI) is a technique used to implement IoC by supplying dependencies from outside rather than creating them inside the class.

Example:

Without DI:

PaymentService paymentService =  new PaymentService();
Enter fullscreen mode Exit fullscreen mode

With DI:

public OrderService(PaymentService paymentService) {
    this.paymentService = paymentService;
}
Enter fullscreen mode Exit fullscreen mode

In Spring Boot, the IoC container (ApplicationContext) creates beans and injects dependencies automatically using constructor injection, thereby implementing IoC through Dependency Injection.

Top comments (0)