Dependency Injection Spring boot

🔹 What is Dependency Injection?

Dependency Injection (DI) is a design pattern where the Spring framework manages the creation and injection of objects (dependencies) into a class instead of the class creating them itself.
This helps achieve loose coupling and makes the code more maintainable and testable.

In Spring Boot, DI can be achieved mainly in three ways:

  1. Constructor Injection (Recommended)
  2. Setter Injection
  3. Field Injection

🔹 Example Scenario

Let’s say we’re building a simple notification system.
We have two services:

  • EmailService (sends emails)
  • SMSService (sends SMS)

A NotificationController depends on these services.


1. Define Service Interfaces

package com.example.demo.service;

public interface MessageService {
    void sendMessage(String recipient, String message);
}

2. Implement the Services

package com.example.demo.service;

import org.springframework.stereotype.Service;

@Service
public class EmailService implements MessageService {
    @Override
    public void sendMessage(String recipient, String message) {
        System.out.println("Sending Email to " + recipient + ": " + message);
    }
}
package com.example.demo.service;

import org.springframework.stereotype.Service;

@Service
public class SMSService implements MessageService {
    @Override
    public void sendMessage(String recipient, String message) {
        System.out.println("Sending SMS to " + recipient + ": " + message);
    }
}

3. Inject Services into a Controller

✅ Constructor Injection (Best Practice)

package com.example.demo.controller;

import com.example.demo.service.MessageService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class NotificationController {

    private final MessageService messageService;

    // Constructor Injection
    public NotificationController(MessageService messageService) {
        this.messageService = messageService;
    }

    @GetMapping("/notify")
    public String sendNotification() {
        messageService.sendMessage("user@example.com", "Hello from Spring Boot!");
        return "Notification Sent!";
    }
}

4. Handling Multiple Implementations

If both EmailService and SMSService implement MessageService, Spring won’t know which one to inject.
We solve this with @Qualifier.

package com.example.demo.controller;

import com.example.demo.service.MessageService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class NotificationController {

    private final MessageService messageService;

    public NotificationController(@Qualifier("emailService") MessageService messageService) {
        this.messageService = messageService;
    }

    @GetMapping("/notify")
    public String sendNotification() {
        messageService.sendMessage("user@example.com", "Hello via Email!");
        return "Notification Sent!";
    }
}

🔹 Key Points

  • Use @Service (or @Component) to mark beans that Spring should manage.
  • Use constructor injection instead of field injection for immutability and easier testing.
  • Use @Qualifier when multiple implementations exist.
  • Spring Boot automatically scans and injects beans in the @SpringBootApplication package and its subpackages.

Leave a Reply