Labs ICT
โญ Pro Login

Dependency Injection

How Spring manages your objects and their dependencies.

Dependency Injection

So you want to learn Spring Boot? Let's start with the big idea that makes everything click: dependency injection. Imagine you're building a car. You could build every single part yourself, but that's a lot of work. Instead, you get the engine from one supplier, the tires from another. You just connect them together. That's dependency injection โ€“ your class gets the objects it needs from the outside instead of creating them internally.

This matters because it makes your code loose. When your class doesn't create its own dependencies, you can swap them out easily. Need a different database? Just change the configuration. Want to use a mock for testing? No problem. This loose coupling makes your application flexible and testable.

Spring Boot's IoC container handles all this for you. IoC stands for Inversion of Control. Instead of you controlling when objects are created, Spring manages their entire lifecycle. You just declare what you need, and Spring provides it. It's like having a personal assistant who knows exactly what tools you need before you even ask.

The beauty of DI is that it makes your code cleaner and more focused. Your classes don't need to know how to create their dependencies โ€“ they just use them. This separation of concerns is a core principle of good software design.

Constructor vs Field Injection

There are two main ways to inject dependencies in Spring. Constructor injection is when you pass dependencies through the constructor. This is the recommended approach because it makes your class immutable and ensures all required dependencies are available when the object is created.

Field injection is when Spring injects dependencies directly into your fields. It's simpler to write but has some downsides โ€“ it makes testing harder and hides the class's true dependencies. Think of it like borrowing tools from a neighbor versus having them delivered to your door.

@Service
public class OrderService {
    
    private final OrderRepository orderRepository;
    
    @Autowired
    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }
    
    public Order createOrder(OrderRequest request) {
        Order order = new Order(request);
        return orderRepository.save(order);
    }
}
Try it Yourself โ†’

Field Injection Example

Here's what field injection looks like. It's shorter to write, but it hides the dependencies. When you look at the class, you can't immediately tell what it needs to work. With constructor injection, the dependencies are explicit in the constructor parameters.

@Service
public class PaymentService {
    
    @Autowired
    private PaymentRepository paymentRepository;
    
    @Autowired
    private EmailService emailService;
    
    public void processPayment(Payment payment) {
        paymentRepository.save(payment);
        emailService.sendReceipt(payment);
    }
}

Field injection also makes testing more complicated. You'd need to use reflection or Spring's test context to inject mocks, whereas constructor injection lets you simply pass mocks directly to the constructor.

Why This Pattern Works

Constructor injection also makes testing straightforward. You can create a mock object and pass it directly to the constructor. No need for reflection or special Spring test contexts. This simplicity is why most Spring developers prefer constructor injection over field injection.

Remember, dependency injection isn't just a Spring feature โ€“ it's a fundamental design pattern. Spring just makes it incredibly easy to implement. Once you grasp this concept, everything else in Spring Boot will make much more sense.

Trust me, invest time understanding this now, and you'll save countless hours debugging later. The loose coupling that DI provides is what makes large applications maintainable and testable.

๐Ÿงช Quick Quiz

What is the Spring IoC container?