What Is Dependency Injection and How Is It Implemented in Spring?

Published: (December 18, 2025 at 10:16 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Introduction

Imagine you buy a new TV, and every time it breaks you have to repair it yourself because all components are tightly welded together. Frustrating, right? Now imagine each part can be replaced independently—much easier to maintain.

This is exactly the problem Dependency Injection (DI) solves in Java programming.

When beginners write Java code, classes often create their own dependencies. This makes applications hard to test, hard to change, and tightly coupled. Spring solves this elegantly using Dependency Injection, one of its core concepts.

In this article you’ll learn what Dependency Injection is, why it’s important, and how Spring implements it using simple, real‑world analogies and clean Java 21 examples. By the end, you’ll understand why DI is considered a foundation of modern Java development.

Core Concepts

What Is Dependency Injection?

At a simple level, Dependency Injection means giving an object what it needs, instead of the object creating it itself.

Analogy: Mobile Charger
Your phone doesn’t manufacture its own charger. You inject the charger into the phone when needed. This allows:

  • Different chargers
  • Easy replacement
  • Better flexibility

In Java, a dependency is usually another class that your class needs to work.

Without Dependency Injection (Tightly Coupled Code)

public class Car {
    private Engine engine = new Engine(); // tightly coupled
}

Problems

  • You can’t change the engine easily
  • Hard to test
  • Code is rigid

With Dependency Injection (Loosely Coupled Code)

public class Car {
    private Engine engine;

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

Now the Engine is injected, not created internally, enabling flexibility and testability.

How Spring Implements Dependency Injection

Spring uses a principle called Inversion of Control (IoC).

  • You define what objects you need.
  • Spring decides how and when to create them.
  • Spring injects dependencies automatically.

Spring supports DI using:

  • Constructor Injection (recommended)
  • Setter Injection
  • Field Injection (not recommended)

Benefits of Dependency Injection in Spring

  • Loose coupling
  • Easier testing (mocking)
  • Better maintainability
  • Cleaner, more readable code
  • Enterprise‑ready architecture

Code Examples (Java 21)

// Dependency
@Component
public class PaymentService {

    public String processPayment() {
        return "Payment processed successfully";
    }
}
// Dependent class
@Component
public class OrderService {

    private final PaymentService paymentService;

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

    public String placeOrder() {
        return paymentService.processPayment();
    }
}

Why this is good

  • Dependencies are explicit
  • Easy to test
  • Immutable and safe

Example 2: Setter Injection (Optional Dependencies)

@Component
public class NotificationService {

    public void notifyUser() {
        System.out.println("User notified");
    }
}
@Component
public class UserService {

    private NotificationService notificationService;

    @Autowired
    public void setNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }

    public void registerUser() {
        notificationService.notifyUser();
    }
}

When to use

  • Useful when the dependency is optional or configurable.

Best Practices

  • Prefer constructor injection – makes dependencies clear and avoids null issues.
  • Avoid field injection – hides dependencies and makes testing difficult.
  • Program to interfaces, not implementations – improves flexibility and testability.
  • Keep beans focused – one class should have one responsibility.
  • Let Spring manage object creation – avoid using new for Spring‑managed beans.

Common Mistakes to Avoid

  • Mixing manual object creation with Spring DI.
  • Overusing @Autowired unnecessarily.
  • Creating circular dependencies.
  • Ignoring interfaces in service design.

Conclusion

Dependency Injection in Spring is not just a framework feature—it’s a design philosophy that makes Java applications clean, flexible, and maintainable.

By letting Spring handle object creation and dependency wiring, you write less boilerplate code and focus more on business logic. Whether you’re building a small REST API or a large enterprise system, mastering Dependency Injection will instantly improve the quality of your Java programming.

Back to Blog

Related posts

Read more »