IoC container, @Component, @Service, @Autowired — the core of Spring.
Published February 3, 2025
Dependency Injection (DI) is how Spring manages object creation and wiring. Instead of using new, Spring creates objects and injects dependencies for you.
Spring's ApplicationContext is the DI container. It:
@Component, @Service, @Repository, @Controller@Component // generic Spring bean
@Service // service-layer logic (same as @Component, communicates intent)
@Repository // data-access layer (also translates DB exceptions)
@Controller // web layer (handles HTTP requests)
@Service
public class OrderService {
private final OrderRepository repository;
private final EmailService emailService;
// Spring injects these — no @Autowired needed on single constructor
public OrderService(OrderRepository repository, EmailService emailService) {
this.repository = repository;
this.emailService = emailService;
}
public Order placeOrder(CreateOrderRequest request) {
Order order = repository.save(new Order(request));
emailService.sendConfirmation(order);
return order;
}
}
Why constructor injection?
final (immutability)@Service
public class OrderService {
@Autowired
private OrderRepository repository; // ❌ avoid — hides dependencies, hard to test
}
@Bean
@ConditionalOnProperty(name = "feature.notifications.enabled", havingValue = "true")
public NotificationService notificationService() {
return new EmailNotificationService();
}
@Component
@Scope("prototype") // new instance per injection (default is "singleton")
public class RequestHandler { ... }
"Always prefer constructor injection over field injection. It makes dependencies explicit, supports immutability, and allows unit testing without Spring context overhead."
Common question: "What is the difference between @Component, @Service, and @Repository?"
Functionally identical — all register a bean. The difference is semantic: @Repository adds exception translation (converts DB-specific exceptions to Spring's DataAccessException hierarchy).