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. 1.Define contract
  2. 2.Create beans
  3. 3.Inject constructor
  4. 4.Use service
  5. 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

DependencyInjectionExample.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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.