Dependency Injection
The class declares what it needs and receives it externally.
These two approaches are often confused because both reduce direct construction in application code. But they are not the same. With DI, dependencies are declared by the class and supplied from outside. With Service Locator, dependencies are fetched from a shared registry or container from inside the class. That difference changes readability, testability, and architectural transparency.
In Java systems, a class that quietly pulls collaborators from a locator can look simple while hiding real dependencies. DI makes those dependencies visible in the class contract, which is why the distinction matters so much during reviews and testing.
Service Locator centralizes access to services, but it does so by making the class reach outward for dependencies. That means the true dependency set is not obvious from the constructor or API. Dependency Injection works the other way around: the class states its needs, and the environment satisfies them. The class contract stays explicit.
That is why DI is usually preferred for modern Java systems. It is not just a stylistic choice. It is a readability and architecture choice.
The class declares what it needs and receives it externally.
The class asks a registry or container for what it needs from inside its own logic.
DI reveals architecture at the class boundary; Service Locator tends to hide it.
package org.javaomnibus.ecommerce.di;
public final class LocatorBasedCheckoutService {
public void place(Order order) {
PaymentGateway paymentGateway = ServiceLocator.resolve(PaymentGateway.class);
paymentGateway.capture(order);
}
}
public final class InjectedCheckoutService {
private final PaymentGateway paymentGateway;
public InjectedCheckoutService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
public void place(Order order) {
paymentGateway.capture(order);
}
}
| Approach | Dependency visibility | Testability | Main risk |
|---|---|---|---|
| Dependency Injection | Explicit | Strong | Oversized constructors reveal design problems clearly |
| Service Locator | Hidden inside the class | Weaker | Architectural coupling becomes easier to conceal |
Service Locator can feel convenient in legacy or plugin-heavy systems, but it usually trades short-term convenience for weaker dependency visibility and harder tests.