Sections in this lesson
Dependency Injection & IoC
Build small services whose collaborators are supplied explicitly and can be replaced in tests.
Reviewed: · Content owner: Interview Preparator
What you will learn
- Explain IoC and constructor injection.
- Distinguish singleton scope from thread safety.
- Test domain behavior with and without a Spring context.
Before you start
The flow
- 1.Define contract
- 2.Create beans
- 3.Inject constructor
- 4.Use service
- 5.Close context
Invert construction responsibilities
A service defines the repository contract it needs; configuration chooses the implementation. The service does not instantiate a database client or look up the application context. Constructor injection makes required collaborators visible and supports final fields.
In the example, TopicService is ordinary Java. A small configuration creates its repository and wires the service. A unit test supplies a lambda without starting Spring; a context test checks actual bean wiring.
Scope is not a lock
The default singleton scope means one bean per Spring container, not one instance across every process and not automatic synchronization. Keep request-specific identity outside mutable singleton fields. A shared ChatClient can be safe while a shared conversation ID still leaks context.
Use qualifiers or explicit bean names when several implementations exist. A circular constructor dependency often signals responsibilities that should be separated rather than hidden through field injection.
Test the appropriate boundary
Test service decisions without a container when possible. Add a focused context test for bean selection and lifecycle. Starting a full web server for every domain test increases feedback time without necessarily exercising a new risk.
Try it
package com.interviewpreparator.lessons;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;public final class DependencyInjectionExample { public interface TopicRepository { String findTitle(String id); } public static final class TopicService { private final TopicRepository repository; public TopicService(TopicRepository repository) { this.repository = repository; } public String title(String id) { return repository.findTitle(id); } } @Configuration public static class Wiring { @Bean TopicRepository topics() { return id -> "Java records"; } @Bean TopicService service(TopicRepository repository) { return new TopicService(repository); } }}examples/spring-ai-lab/src/main/java/com/interviewpreparator/lessons/DependencyInjectionExample.java · mvn -f examples/spring-ai-lab/pom.xml test. Java 21+, Spring Boot 4.0.5, Spring AI 2.0.2 where applicable. The demo uses synthetic models; live inference quality is a separate check.
Interview questions
What does IoC invert?
The object stops controlling collaborator construction; the composition layer supplies dependencies.
Is a singleton bean thread-safe?
Only if its design is thread-safe; scope alone provides no locking.
Why test without Spring?
To isolate domain behavior and keep feedback fast while using separate wiring tests for the container.
Practice
Add a second repository implementation and select it explicitly for one service.
Check your solution
- Domain tests run without a context.
- A context test proves the selected implementation.
- No request state is stored in singleton fields.
Official references
Continue learning
Category sequence
Spring & Spring Boot
Lesson 1 / 4
Was this lesson useful?
Change notes: Phase 2: bilingual lesson with versioned executable reference.