Spring Boot + Spring Core
How does Spring Dependency Injection actually work?
Spring creates and manages objects called beans, figures out what each bean depends on, and injects those dependencies when it creates the bean.
The Short Answer
Spring Dependency Injection means your class does not create its own dependencies. Instead, it declares what it needs, and Spring provides those dependencies when it creates the object.
The important idea is this: your application code no longer controls object creation directly. Spring's container does.
The Real Problem Spring Solves
Imagine a service class that needs a repository, a validator, a clock, a metrics recorder, and maybe a client for another API.
Without dependency injection, code often turns into this:
public class OrderService {
private final OrderRepository repository = new OrderRepository();
private final PaymentClient paymentClient = new PaymentClient();
private final MetricsRecorder metrics = new MetricsRecorder();
public void placeOrder(Order order) {
// business logic
}
}This looks simple at first, but the class is now tightly coupled to concrete implementations. Testing is harder, replacing dependencies is harder, and configuration becomes scattered everywhere.
Tight Coupling
The service chooses exact implementations instead of depending on abstractions.
Hard Testing
Replacing real dependencies with test doubles becomes awkward.
Scattered Setup
Object creation and configuration get spread across business code.
The Mental Model
Without Spring DI
The class controls object creation. It is coupled to specific implementations.
With Spring DI
Spring creates the dependencies and passes them into your class. Your class focuses on business logic.
What Happens at Startup?
At a high level, Spring Boot starts the application, scans for components, builds bean definitions, creates beans, resolves their dependencies, and wires everything together.
Step 1
Start app
Step 2
Scan components
Step 3
Create bean definitions
Step 4
Resolve dependencies
Step 5
Instantiate beans
Step 6
Inject dependencies
This is why a class annotated with @Service can be injected into a controller without you manually creating it. Spring discovered it, registered it as a bean, and made it available to other beans.
Constructor Injection Example
Constructor injection is usually the cleanest way to express required dependencies.
@Service
public class OrderService {
private final OrderRepository repository;
private final PaymentClient paymentClient;
public OrderService(
OrderRepository repository,
PaymentClient paymentClient
) {
this.repository = repository;
this.paymentClient = paymentClient;
}
public void placeOrder(Order order) {
// business logic
}
}Notice that OrderService does not call new OrderRepository(). It simply declares what it needs.
How Does Spring Know What to Inject?
Spring looks inside its application context for a matching bean. If the constructor needs an OrderRepository, Spring searches for a bean of that type.
@Repository
public class JpaOrderRepository implements OrderRepository {
// database logic
}Because this class is annotated with @Repository, component scanning can discover it and register it as a bean.
@Component, @Service, and @Repository
These annotations all register classes as Spring-managed beans, but they communicate intent.
@Component
Generic Spring-managed component.
@Service
Business/service-layer component.
@Repository
Persistence/data-access component.
For interview purposes, it is useful to say that these are stereotype annotations. They help Spring discover beans and help humans understand the role of a class.
@Bean vs @Component
Use @Component when the class is yours and can be annotated directly.
Use @Bean when you want to create a bean manually, often for third-party classes or configuration-heavy objects.
@Configuration
public class AppConfig {
@Bean
public Clock clock() {
return Clock.systemUTC();
}
}Here, Clock is not your custom Spring component. You are telling Spring: “Call this method and register the returned object as a bean.”
Common Interview Trap: Is DI Magic?
It can feel like magic because you do not call constructors manually. But the idea is straightforward:
What If There Are Multiple Beans of the Same Type?
If Spring finds exactly one matching bean, injection is simple. If it finds multiple candidates, it needs help deciding.
You can resolve ambiguity with names, qualifiers, or primary beans.
@Service
public class NotificationService {
private final MessageSender sender;
public NotificationService(
@Qualifier("emailSender") MessageSender sender
) {
this.sender = sender;
}
}Common Interview Follow-Ups
Why is constructor injection preferred?
It makes required dependencies explicit, supports final fields, improves testability, and avoids partially initialized objects.
Does Spring create every object in your application?
No. Spring only manages objects registered as beans. Plain objects created with new are not automatically Spring-managed.
What is the difference between IoC and DI?
IoC is the broader principle: control of object creation is inverted. DI is the common technique Spring uses to implement that principle.
What happens if a dependency is missing?
Spring fails at startup because it cannot construct the bean that requires the missing dependency.
Final Takeaway
new. It is about moving object creation, wiring, configuration, and lifecycle management into the Spring container so your classes stay focused, testable, and loosely coupled.