How does Spring MVC utilize dependency injection with controllers?

Spring MVC controllers rely on Spring's IoC container to supply their dependencies — services, repositories, and other components — rather than constructing them manually. This is the same dependency injection mechanism used throughout the framework, applied to the web layer.

Key Points: • @Controller (or @RestController) marks a class as a Spring-managed bean, making it eligible for dependency injection. • Constructor injection is the recommended style, since it makes dependencies explicit and supports immutability with final fields. • @Autowired can also be used on fields or setters, though field injection is generally discouraged for testability reasons. • Spring resolves dependencies by type, and @Qualifier can disambiguate when multiple beans implement the same interface. • Because dependencies are injected rather than hard-coded, controllers can be unit tested by passing in mocks instead of real service implementations.

Example: A controller that needs to look up products declares a final ProductService field set through its constructor; Spring automatically supplies the real ProductService bean when the application starts, and a test can supply a Mockito mock instead.

Code Example:

@RestController
public class ProductController {

    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping("/products/{id}")
    public Product getProduct(@PathVariable Long id) {
        return productService.findById(id);
    }
}

Interview Tip: A concise interview answer is:

"Spring MVC controllers get their dependencies through the same IoC container as everything else — I prefer constructor injection so dependencies are explicit and the class can be tested with mocks. Spring resolves the beans by type at startup, so the controller never has to instantiate its services itself."