Spring BootDependency Injectionintermediate
Updated:

Spring Boot Dependency Injection Interview Questions and Answers

7 min read

Dependency injection interviews test IoC, constructor injection, qualifier resolution and circular dependencies. Here are the questions asked with correct code.

TL;DR – Quick Answer

Dependency injection interviews test whether you understand inversion of control and how Spring wires beans. Expect the IoC and DI concept, constructor versus setter versus field injection and why constructor injection is preferred, the stereotype annotations, @Configuration and @Bean, resolving ambiguity with @Qualifier and @Primary, injecting collections of beans, handling optional dependencies, and diagnosing circular dependencies. Being able to write clean constructor injection and explain why it is best is the core of the grade.

On This Page

Dependency injection is the idea the entire Spring framework is built on, so interviewers treat it as a foundation test: get it wrong and everything above it — beans, AOP, transactions — is shaky. The questions look simple but reward candidates who can explain why constructor injection is preferred and how the container resolves ambiguity, not just recite definitions. This set covers the DI questions asked in intermediate Spring Boot rounds, with correct, current code.

What is Inversion of Control and dependency injection?

Inversion of Control is the principle that the framework, not your code, controls object creation and the flow of the program. Dependency injection is the specific technique that applies IoC to dependencies: instead of a class building its own collaborators with new, the container creates them and hands them in.

Concretely, without DI an OrderService would do this.repo = new OrderRepository(), hard-wiring itself to a concrete class it cannot swap or mock. With DI, the container creates the repository and injects it, so OrderService depends on an abstraction it receives. The control over what it gets is inverted to the container.

The payoff is testability and flexibility: you can inject a real implementation in production and a fake in a test, without the class knowing the difference.

What are the types of dependency injection in Spring?

Three: constructor injection (dependencies passed to the constructor), setter injection (supplied through setter methods after construction), and field injection (@Autowired directly on a field, set via reflection). Constructor injection is the recommended default.

Each has a shape. Constructor injection guarantees the object is complete the moment it exists. Setter injection allows optional or reconfigurable dependencies. Field injection is the most concise to write but the weakest by every other measure. Knowing all three exist — and having a firm opinion on which to use — is the expected answer.

Why is constructor injection preferred?

Because it makes dependencies final and mandatory, so the object is immutable and fully valid once constructed; it fails fast at startup if a required bean is missing rather than throwing an NPE later; it needs no reflection; and it lets you build the class in a unit test with a plain new, no Spring context required.

@Service
public class OrderService {

    private final OrderRepository repository;
    private final PaymentGateway payments;

    // Single constructor: @Autowired not needed since Spring 4.3
    public OrderService(OrderRepository repository, PaymentGateway payments) {
        this.repository = repository;
        this.payments = payments;
    }
}

Field injection, by contrast, cannot make fields final, hides dependencies (a class with ten @Autowired fields looks small but is heavy), and forces tests to use reflection or a full context to set collaborators. A subtle bonus of constructor injection: if the class accumulates too many parameters, the ugly constructor is a visible warning that the class does too much — field injection hides that smell.

Interview note: Follow-up: "so is field injection ever acceptable?" It is mostly confined to test code or quick prototypes; in production code constructor injection is the standard, and many teams enforce it with a linter. Say that and you sound like you have shipped code.

Is @Autowired required, and how does it behave with one constructor?

No. Since Spring 4.3, a class with a single constructor is used for injection automatically, so @Autowired is optional there. You still need it to pick a constructor when there are several, or on setter and field injection.

This is why the modern example above has no annotation on the constructor and still gets its dependencies. Interviewers ask this to check that your knowledge is current — writing @Autowired on every single constructor is harmless but dated. The reason it became optional is that a single constructor is unambiguous: there is exactly one way to build the object.

What are the stereotype annotations?

@Component is the generic "make this a Spring bean" marker. @Service, @Repository and @Controller (and @RestController) are specialisations of @Component that also document the layer. @Repository additionally enables persistence exception translation; @Controller/@RestController participate in web request handling.

Functionally they all register a bean during component scanning, so you could use @Component everywhere. You do not, because the specific stereotype communicates intent — anyone reading @Service knows it is business logic, @Repository knows it is data access — and because @Repository's exception translation converts vendor-specific database exceptions into Spring's consistent DataAccessException hierarchy.

Interview note: Trap: "what does @Repository do that @Component does not?" Exception translation. It is the one stereotype with behaviour beyond documentation, and it is a favourite checkpoint.

When do you use @Configuration and @Bean?

@Component scanning works when you own the class and can annotate it. When you need to register a bean you cannot annotate — a third-party class — or need custom construction logic, you write a @Bean method inside a @Configuration class that builds and returns the object.

@Configuration
public class AppConfig {

    @Bean
    ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());   // custom setup
        return mapper;
    }
}

@Component says "container, instantiate this class for me"; @Bean says "container, call this method and manage what it returns." The @Bean route is essential for library types like ObjectMapper, RestClient or a DataSource that you configure by hand.

How do you resolve multiple beans of the same type — @Qualifier vs @Primary?

When two beans implement the same interface, injection is ambiguous. @Primary on one bean marks it the default choice. @Qualifier("name") at the injection point names exactly which bean to inject. If both are present, @Qualifier wins because it is explicit.

@Service
public class NotificationService {

    private final MessageSender sender;

    public NotificationService(@Qualifier("smsSender") MessageSender sender) {
        this.sender = sender;   // explicitly the SMS implementation
    }
}

Use @Primary when there is a sensible default most callers want, and @Qualifier when a particular injection point needs a specific one. Without either, Spring throws NoUniqueBeanDefinitionException at startup — a fail-fast error, which is exactly the behaviour you want.

Interview note: Follow-up: "can you inject all implementations at once?" Yes — inject List<MessageSender> to get every bean of that type, or Map<String, MessageSender> to get them keyed by bean name. This is the standard pattern for a registry of strategies.

How do you handle optional dependencies?

Three idiomatic options: @Autowired(required = false) leaves the field null if no bean exists; Optional<T> injects an empty optional; and ObjectProvider<T> gives lazy, on-demand access and safe handling of zero-or-many beans. ObjectProvider is the most flexible for optional or plural dependencies.

@Service
public class ReportService {

    private final ObjectProvider<AuditSink> auditSinks;

    public ReportService(ObjectProvider<AuditSink> auditSinks) {
        this.auditSinks = auditSinks;
    }

    void run() {
        auditSinks.ifAvailable(sink -> sink.record("report run"));
    }
}

The reason to prefer ObjectProvider over @Autowired(required=false) is that it does not force you to null-check, defers resolution until you actually ask, and has methods for "if present" and "for each" that read cleanly.

What causes a circular dependency and how do you fix it?

A circular dependency is when bean A needs B and B needs A. With constructor injection Spring cannot build either first, so it fails fast at startup with an error naming the cycle. The right fix is to break the cycle by design; workarounds like @Lazy or setter injection only paper over it.

The strongest answer leads with design: extract the shared logic both beans need into a third bean, or rethink responsibilities so the dependency runs one direction only — a cycle usually means two classes are entangled and should be reorganised. Only after saying that do you mention the mechanical escapes: @Lazy on one dependency injects a proxy that defers resolution, or switching one side to setter/field injection lets Spring construct both then wire them. Note that as of Spring Boot 2.6+, circular references are disallowed by default, reinforcing that they are a smell to remove, not tolerate.

Interview note: Trap: "constructor injection can't do circular dependencies — is that a weakness?" It is a strength. The failure surfaces the design problem at startup instead of hiding it, which is exactly why constructor injection is preferred.

ApplicationContext vs BeanFactory — what is the difference?

BeanFactory is the basic container providing DI and lazy bean instantiation. ApplicationContext extends it with the enterprise features you actually use: eager singleton creation at startup, event publishing, internationalisation, annotation and @Configuration support, and easy integration with AOP. In a Spring Boot app you always work with an ApplicationContext.

The interview point is that ApplicationContext is a superset — everything BeanFactory does, plus the container features that make Spring, Spring. BeanFactory is a low-level building block you rarely touch directly. A practical consequence is eager initialisation: an ApplicationContext creates singletons at startup, so a misconfigured bean fails immediately rather than on first use.

What interviewers really test

Dependency injection questions reward candidates who treat DI as a design tool, not a set of annotations. The clearest signal is arguing for constructor injection on concrete grounds — immutability, fail-fast startup, testability without a context — and treating circular dependencies as a design smell to remove rather than a Spring quirk to work around. Interviewers also check currency: knowing @Autowired is optional on a single constructor, and that Spring Boot now forbids circular references by default.

To prepare, refactor a class from field injection to constructor injection and feel how it becomes testable with a plain new, then deliberately create a circular dependency and read the startup error. The Spring Boot learning path covers the container concepts these questions build on, and this pairs naturally with the bean lifecycle and bean scopes interview sets, since injection, lifecycle and scope are three views of the same container. A mock interview is the fastest way to practise defending your injection choices out loud.

Frequently Asked Questions

What is the difference between IoC and dependency injection?
Inversion of Control is the general principle that a framework, not your code, controls object creation and flow. Dependency injection is the specific technique that implements it for dependencies: instead of a class creating its collaborators, the container creates them and supplies them. DI is one concrete form of IoC.
Why is constructor injection preferred over field injection?
Constructor injection makes dependencies final and mandatory, so the object is fully valid once built, immutable, and fail-fast when a dependency is missing. It needs no reflection to set fields and lets you construct the class in a unit test with plain new. Field injection hides dependencies and cannot enforce immutability.
Is @Autowired required on a constructor?
No. Since Spring 4.3, if a class has a single constructor, Spring uses it for injection without @Autowired. You only need @Autowired to disambiguate when multiple constructors exist, or on setter and field injection. Omitting it on a single constructor is the modern, clean style.
What is the difference between @Qualifier and @Primary?
Both resolve the ambiguity of multiple beans of the same type. @Primary marks one bean as the default chosen when no qualifier is given. @Qualifier names a specific bean at the injection point. @Qualifier is more explicit and wins when both are present, while @Primary is a convenient fallback default.
How do you fix a circular dependency in Spring?
The real fix is to break the cycle: extract the shared logic into a third bean, or rethink the responsibilities so A and B do not need each other. As a workaround you can use setter or field injection, or @Lazy on one dependency, but a circular dependency usually signals a design problem worth removing.

Want to Build Your Career in Java Full Stack with AI?

Join CodeBegun and train with working industry engineers — View the Java Full Stack curriculum

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 16 July 2026 LinkedIn
Chat with us