Java Lesson 53 – Spring DI | Dataplexa

Spring Dependency Injection (DI)

In the previous lesson, you understood the idea of Inversion of Control (IoC). Now we move one step deeper and learn how Spring actually implements IoC — using Dependency Injection (DI).

Dependency Injection is the core mechanism that allows Spring to manage relationships between objects cleanly and efficiently.


What Is Dependency Injection?

Dependency Injection means providing dependencies from the outside instead of creating them inside a class.

A dependency is simply an object that another object needs to function.

In Spring, dependencies are injected by the framework automatically.


Why Dependency Injection Matters

Without DI, Java applications quickly become tightly coupled and hard to maintain.

With DI, classes become:

  • Easier to modify
  • Easier to test
  • More reusable
  • Cleaner in design

This is why DI is used in almost every modern enterprise Java application.


Real-World Example Without DI

Imagine an application that sends notifications.


public class EmailService {
    public void sendEmail() {
        System.out.println("Sending email");
    }
}

public class NotificationService {
    EmailService emailService = new EmailService();

    public void notifyUser() {
        emailService.sendEmail();
    }
}

Here, NotificationService is tightly coupled to EmailService.

Switching to SMS or WhatsApp requires code changes.


Same Example With Dependency Injection

Now let Spring handle the dependency.


public class NotificationService {

    private EmailService emailService;

    public NotificationService(EmailService emailService) {
        this.emailService = emailService;
    }

    public void notifyUser() {
        emailService.sendEmail();
    }
}

The dependency is injected from outside.

Spring decides which implementation to provide.


Types of Dependency Injection in Spring

Spring supports three main types of dependency injection.

  • Constructor Injection
  • Setter Injection
  • Field Injection

Each approach has its use cases.


Constructor Injection (Recommended)

Constructor Injection is the most recommended approach in Spring.


@Component
public class OrderService {

    private final PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

This approach ensures dependencies are available at object creation time.


Setter Injection

Setter Injection injects dependencies using setter methods.


@Component
public class OrderService {

    private PaymentService paymentService;

    @Autowired
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

This is useful when dependencies are optional.


Field Injection (Not Recommended)

Field Injection injects dependencies directly into fields.


@Component
public class OrderService {

    @Autowired
    private PaymentService paymentService;
}

While simple, this approach makes testing harder and is not recommended for large systems.


@Autowired Annotation

The @Autowired annotation tells Spring to inject a dependency automatically.

Spring resolves dependencies by type first and then by name if needed.


How Spring Finds Dependencies

Spring scans the application for components using annotations like:

  • @Component
  • @Service
  • @Repository
  • @Controller

These annotations register classes as Spring beans.


Dependency Injection and Testing

DI makes testing easier because dependencies can be mocked.

This allows developers to test business logic without real database or API calls.


Industry Usage

All modern Spring applications rely heavily on DI.

Microservices, REST APIs, and enterprise systems use DI to stay flexible and scalable.


What Comes Next?

Now that you understand Dependency Injection, the next lesson will show how Spring manages beans using Spring Bean Configuration.

You will see how beans are created, configured, and controlled.