📌 spring-note-002: Understanding IoC (Inversion of Control) & DI (Dependency Injection)
Hunor Vadasz-Perhat

Hunor Vadasz-Perhat @hunor85

About: Software Engineer II @DXC Technology

Location:
Denmark
Joined:
Jul 3, 2023

📌 spring-note-002: Understanding IoC (Inversion of Control) & DI (Dependency Injection)

Publish Date: Feb 11
0 0

(Reference: Spring Docs - IoC Container)


🔹 What is IoC (Inversion of Control)?

💡 IoC is a design principle where the control of object creation and management is shifted from the developer to the framework (Spring).

🛠️ Before IoC: Traditional Object Creation (Manual Control)

public class PirateShip {
    private Captain captain;

    public PirateShip() {
        this.captain = new Captain(); // MANUAL CREATION
    }
}
Enter fullscreen mode Exit fullscreen mode

Problem: The class creates its own dependencies, leading to tight coupling (harder to test & maintain).


⚡ IoC in Action: Spring Controls Object Creation

With IoC, Spring is responsible for creating and injecting dependencies instead of the developer doing it manually.

@Component
public class Captain {
    public String getCommand() {
        return "Set sail, Matey! ☠️";
    }
}

@Component
public class PirateShip {
    private final Captain captain;

    @Autowired
    public PirateShip(Captain captain) {
        this.captain = captain;
    }

    public String sail() {
        return captain.getCommand();
    }
}
Enter fullscreen mode Exit fullscreen mode

💡 Spring injects the Captain instance into PirateShip automatically.


🔹 What is Dependency Injection (DI)?

💡 Dependency Injection (DI) is how Spring implements IoC—it automatically provides the required dependencies to objects.

✅ No new keyword needed.

✅ Objects are loosely coupled (easier to test & modify).

✅ Easier configuration via annotations or XML.


📌 Types of Dependency Injection in Spring

(Reference: Spring Docs - Dependency Injection)

1️⃣ Constructor Injection (Recommended)

🚀 Inject dependencies via constructor (Best Practice).

@Component
public class PirateShip {
    private final Captain captain;

    @Autowired
    public PirateShip(Captain captain) { // Injecting dependency via constructor
        this.captain = captain;
    }
}
Enter fullscreen mode Exit fullscreen mode

Best for mandatory dependencies.

Ensures immutability (final fields).


2️⃣ Setter Injection

🚀 Inject dependencies via setter methods.

@Component
public class PirateShip {
    private Captain captain;

    @Autowired
    public void setCaptain(Captain captain) { // Setter-based injection
        this.captain = captain;
    }
}
Enter fullscreen mode Exit fullscreen mode

Good for optional dependencies.

Can lead to mutable objects (less safe).


3️⃣ Field Injection (NOT Recommended)

⚠️ Directly injecting fields using @Autowired.

@Component
public class PirateShip {
    @Autowired
    private Captain captain;
}
Enter fullscreen mode Exit fullscreen mode

Considered a bad practice because:

  • Harder to test (no way to pass a mock in tests).
  • Breaks immutability (makes class state changeable).

🔥 Best Practice: Use Constructor Injection whenever possible!


📌 Hands-On Project: IoC & DI in Action

Step 1: Create a Spring Boot Project

1️⃣ Go to Spring Initializr

2️⃣ Select:

  • Spring Boot Version: Latest stable
  • Dependencies: Spring Web
  • Packaging: Jar 3️⃣ Click Generate and extract the zip file.

Step 2: Define Components

📌 Create a Captain component:

package com.example.springdi;

import org.springframework.stereotype.Component;

@Component
public class Captain {
    public String giveOrder() {
        return "All hands on deck, Matey! ☠️";
    }
}
Enter fullscreen mode Exit fullscreen mode

📌 Create a PirateShip component that depends on Captain:

package com.example.springdi;

import org.springframework.stereotype.Component;

@Component
public class PirateShip {
    private final Captain captain;

    public PirateShip(Captain captain) {
        this.captain = captain;
    }

    public String sail() {
        return captain.giveOrder();
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a REST Controller

📌 Expose the PirateShip behavior via an API:

package com.example.springdi.controller;

import com.example.springdi.PirateShip;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/pirates")
public class PirateController {
    private final PirateShip pirateShip;

    public PirateController(PirateShip pirateShip) {
        this.pirateShip = pirateShip;
    }

    @GetMapping("/sail")
    public String sail() {
        return pirateShip.sail();
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Run the Application

💡 Run the app using:

mvn spring-boot:run
Enter fullscreen mode Exit fullscreen mode

or

./mvnw spring-boot:run
Enter fullscreen mode Exit fullscreen mode

🌐 Visit: http://localhost:8080/pirates/sail

🎉 You should see:

All hands on deck, Matey! ☠️
Enter fullscreen mode Exit fullscreen mode

📌 Summary

IoC = Spring takes control of object creation and lifecycle.

DI = Injecting dependencies instead of creating them manually.

Constructor Injection is best practice!

We built a real Spring Boot app demonstrating DI!

📌 Topics Covered in This Section
📜 IoC & Dependency Injection (✔️ Covered)

  • What is IoC? (Spring manages object creation, inversion of control).
  • What is DI? (Spring injects dependencies, reducing coupling).
  • Spring’s IoC container (ApplicationContext & BeanFactory).
  • Types of DI: Constructor, Setter, Field Injection (Pros/Cons).
  • Best Practices: Constructor Injection > Setter Injection > Field Injection.

🛠️ Spring Boot & IoC (✔️ Covered)

  • Auto-Configuration & @Component Scanning.
  • @Autowired behavior and limitations.
  • How IoC integrates into a Spring Boot project.

🔥 Key Takeaways You Need to Remember for the Exam:
✅ Spring’s IoC container creates, configures, and manages objects (beans).
✅ DI eliminates the need for new keyword by injecting dependencies.
✅ Spring Boot automatically registers components using @ComponentScan.
✅ @Autowired is used for injection but Constructor Injection is best practice.

Comments 0 total

    Add comment