Spring Boot Interview Questions

Reviewed by Mark Dickie · Last updated

12 questions on this page you can answer and see marked on the spot. Go to the first one

Spring Boot is a Java framework that creates stand-alone, production-grade Spring applications with minimal setup by providing convention-over-configuration defaults, an embedded servlet container, and a large library of ready-made starters. For an interview you should know how auto-configuration works under the hood via conditional annotations, how the component-lifecycle and bean-injection mechanisms differ, and how to override or exclude specific auto-configurations. Examiners also expect you to explain Actuator endpoints, profile-based externalized configuration, and the testing support that Spring Boot provides out of the box.

What does a Spring Boot interview typically test?

AreaWhat you should be able to explain
Auto-configurationHow @EnableAutoConfiguration triggers conditional bean registration and how to exclude or override specific classes
StartersWhat a POM starter bundles and why convention over configuration reduces boilerplate
`Dependency injectionThe difference between constructor, setter, and field injection and when constructor injection is preferred
Externalized configThe property-source order (command-line args, environment, application.yml, defaults) and how @ConfigurationProperties binds nested keys
ActuatorWhich endpoints ship by default, how to enable or secure them, and how /health integrates with cloud readiness probes
TestingSlicing with @WebMvcTest and @DataJpaTest versus full-context @SpringBootTest, and how MockMvc fits in

Which concepts come up most often?

  1. Conditional annotations (@ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty) and how they decide which beans get created.
  2. The difference between @Component, @Service, @Repository, and @Controller at the stereotype level, and why they are functionally identical but semantically distinct.
  3. How the embedded Tomcat, Jetty, or Undertow server boots and how to switch or disable it.
  4. Profile activation through spring.profiles.active, the @Profile annotation, and multi-document YAML files.
  5. Graceful shutdown, health checks, and the readiness/liveness split introduced for container orchestration platforms.

Key facts

  • Tarmac has 223 Spring Boot interview questions on this topic, 25 of them on this page, at difficulty 1–5 of 5.
  • Tarmac tracked 652 job postings asking for Spring Boot in September 2026.
  • Roles asking for Spring Boot advertise a median base salary of £75,000, across 145 job postings as of September 2026.
  • Tarmac last reviewed these Spring Boot interview questions on 20 October 2026.

At a glance

Questions25 shown · 223 in the bank
Difficulty1–5 of 5
FormatsTrue / false, Multiple choice, Find the bug, Ordering, Short answer, Fill in the blank, Multiple answer, Code output, Flashcard

What you'll review

  1. bean scopes and lifecycle
  2. beans and the application context
  3. resilience and circuit breakers spring
  4. constructor vs field injection

Practice questions

Try one before you open the answer. Pick an option and press Check; it's marked on the spot.

In Spring Boot, the default scope for a bean annotated with @Component is singleton, meaning the container creates exactly one instance of that bean and returns the same instance on every injection point.#

Options

Show answer

True. In Spring Boot, the default bean scope is singleton, so the container creates one instance of a @Component bean and reuses it for every injection point. To change this behavior you must explicitly set a different scope such as @Scope("prototype").

Why:

Spring's default bean scope is singleton. When you annotate a class with @Component (or @Service, @Repository, etc.) and do not specify a scope, the container instantiates one instance per application context and serves that same instance wherever the bean is injected.

A method annotated with @PostConstruct in a Spring-managed bean is invoked by the container after dependency injection is complete, but before the bean is placed into service.#

Options

Show answer

True. Spring calls a @PostConstruct method after all of the bean's dependencies have been injected and before the bean is placed into service, so it is the standard hook for post-construction initialization logic.

Why:

@PostConstruct is a standard lifecycle annotation (JSR-250) that Spring honors. The container calls the annotated method after all dependencies have been injected and before the bean is made available for use, making it the correct place for initialization logic.

In a Spring Boot application with component scanning enabled, which annotation is applied at the class level to tell Spring to register an instance of that class as a managed bean in the application context?#

Options

Show answer

@Component is the class-level stereotype annotation that tells Spring's component scanner to register the class as a managed bean. @Bean is method-level inside a @Configuration class, @Autowired marks an injection point, and @Configuration marks a config class rather than the bean itself.

Why:

@Component is a stereotype annotation placed on a class so that Spring's component scanner discovers it and registers a bean definition in the application context. @Bean is a method-level annotation used inside @Configuration classes, @Autowired declares an injection point rather than a bean definition, and @Configuration marks a class as a source of bean declarations, not the bean itself.

When you declare a bean in a Spring Boot application context and do not specify a scope, what is the default scope that Spring assigns to that bean?#

Options

Show answer

The default bean scope in Spring is singleton. When no scope is specified, the application context creates a single shared instance of the bean and injects that same instance everywhere. Prototype, request, and session scopes must be declared explicitly with @Scope.

Why:

The default bean scope in Spring is singleton, meaning the application context creates and caches exactly one instance of the bean and returns that same instance for every injection point. prototype creates a new instance each time, while request and session are web-scoped and must be declared explicitly.

In Spring Boot, which interface represents the primary IoC container that manages bean definitions, instantiates beans, and wires their dependencies?#

Options

Show answer

ApplicationContext is the primary IoC container in Spring Boot. It extends BeanFactory with additional enterprise features and is the container that Spring Boot auto-configures at startup to manage bean definitions, instantiation, and dependency wiring.

Why:

ApplicationContext is the primary IoC container interface in Spring Boot; it extends BeanFactory and adds enterprise features such as event publication, internationalization, and resource loading. BeanFactory is the more minimal root interface but is not the container Spring Boot boots by default. DispatcherServlet handles HTTP requests, and Environment provides property and profile information.

The following Spring Boot service uses Resilience4j's @CircuitBreaker to protect a remote call. A runtime error occurs because the fallback method is declared incorrectly. Identify the single buggy line (1-based line number).#

@Service
public class PaymentService {

    @CircuitBreaker(name = "paymentService", fallbackMethod = "fallback")
    public String processPayment(String orderId) {
        return paymentClient.charge(orderId);
    }

    public String fallback() {
        return "default-payment";
    }
}
Show answer

The bug is on line 9.

Why:

Resilience4j requires the fallback method to accept the same parameters as the original method (optionally followed by a Throwable). processPayment takes a String orderId, but fallback() on line 9 takes no parameters. The fix is public String fallback(String orderId) {. At runtime Resilience4j throws an IllegalArgumentException because it cannot find a compatible fallback method matching the original method's parameter types.

The Spring Boot service below uses Resilience4j @CircuitBreaker with a fallback. The circuit breaker fails to wire up the fallback at application startup. Which line contains the bug?#

@Service
public class InventoryService {

    @CircuitBreaker(name = "inventoryService", fallbackMethod = "getDefualtInventory")
    public List<Item> getInventory(String sku) {
        return inventoryClient.fetch(sku);
    }

    public List<Item> getDefaultInventory(String sku, Exception e) {
        return Collections.emptyList();
    }
}

Options

Show answer

Line 4 — the fallbackMethod value is misspelled: "getDefualtInventory" does not match the actual method name "getDefaultInventory".

Why:

On line 4 the fallbackMethod attribute is set to "getDefualtInventory" — a typo. The actual method on line 9 is named getDefaultInventory. Resilience4j resolves the fallback by the exact name supplied in the annotation; since no method named getDefualtInventory exists, startup fails with an IllegalArgumentException. The fallback method's signature itself (same first parameter String sku plus an Exception trailing parameter, matching return type List<Item>) is correct, so the only defect is the misspelled name on line 4.

Order the phases of the Spring bean lifecycle as they relate to dependency injection, from earliest to latest. Each phase describes when a specific injection mechanism or callback takes effect.#

Put these in order

Show answer

Constructor injection happens first (during bean instantiation), then field/setter injection during property population, then the @PostConstruct callback, and finally the bean is ready for use. This order follows Spring's standard bean lifecycle, where the object must exist before its fields can be set and before post-construction hooks fire.

Why:

Spring instantiates a bean by calling its constructor, which is when constructor-injected dependencies are resolved. Only after the object exists can Spring populate @Autowired fields and call setters during the property-population phase. Once all injection is complete, Spring invokes @PostConstruct. The bean is then fully initialized and ready for use.

Order the sequence of events when Spring encounters a circular dependency between two beans that both use constructor injection (Bean A needs Bean B, and Bean B needs Bean A).#

Put these in order

Show answer

Spring starts creating Bean A, finds it needs Bean B, starts creating Bean B, finds it needs Bean A, detects the deadlock, and throws BeanCurrentlyInCreationException. Constructor injection cannot resolve circular dependencies because no early bean reference exists before the constructor runs, so Spring fails fast.

Why:

Spring starts creating Bean A, but its constructor requires Bean B. It pauses A and tries to create B, whose constructor requires Bean A. Because A is not yet constructed (no early reference is available for constructor injection, unlike field injection), Spring detects the deadlock and throws BeanCurrentlyInCreationException. This is why constructor injection prevents circular dependencies.

In Spring Boot, what is the default scope assigned to a bean when you annotate a class with @Component (or @Service, @Repository) and do not specify any scope annotation? Give the exact scope name.#

Show answer

singleton

Why:

When no @Scope annotation is present, the Spring container creates a single shared instance of the bean per application context (per bean name). This is the singleton scope, which is the default for all beans registered via stereotype annotations or @Bean methods.

Spring Boot provides two JSR-250 / jakarta.annotation lifecycle callback annotations that let you run initialization logic right after dependency injection and cleanup logic just before the bean is removed from the application context. Give the annotation names in order: initialization first, then cleanup.#

Show answer

@PostConstruct (initialization) and @PreDestroy (cleanup)

Why:

@PostConstruct is invoked by the container after the bean's dependencies have been injected, making it the standard place for init logic. @PreDestroy is invoked before the bean is destroyed, allowing resource cleanup. Both are from jakarta.annotation (formerly javax.annotation) and are supported natively by Spring's CommonAnnotationBeanPostProcessor.

In Resilience4j (the default circuit-breaker implementation in Spring Cloud Circuit Breaker), a circuit breaker begins in the _____ state, allowing calls to flow through normally. When the configured failure-rate threshold is exceeded, it transitions to the _____ state, which short-circuits all subsequent calls until a configured wait-time period has elapsed.#

Show answer

In Resilience4j (the default circuit-breaker implementation in Spring Cloud Circuit Breaker), a circuit breaker begins in the CLOSED state, allowing calls to flow through normally. When the configured failure-rate threshold is exceeded, it transitions to the OPEN state, which short-circuits all subsequent calls until a configured wait-time period has elapsed.

Why:

A Resilience4j circuit breaker uses a three-state machine. It starts in CLOSED, where all calls are permitted and outcomes are recorded in a sliding window. Once the failure rate crosses the configured threshold (default 50%), the breaker trips to OPEN and immediately rejects calls by throwing a CallNotPermittedException. It remains OPEN for the configured wait-duration-in-open-state before transitioning toward HALF_OPEN.

In a Spring Boot application using Resilience4j, you enable a circuit breaker on a service method by applying the _____ annotation. When the breaker is open or a call fails, you can redirect execution to a backup method by setting the annotation's _____ attribute to the name of that method.#

Show answer

In a Spring Boot application using Resilience4j, you enable a circuit breaker on a service method by applying the @CircuitBreaker annotation. When the breaker is open or a call fails, you can redirect execution to a backup method by setting the annotation's fallbackMethod attribute to the name of that method.

Why:

The @CircuitBreaker annotation (from io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker) is the declarative way to wrap a method in a circuit breaker. Its fallbackMethod attribute names a method (same signature, optionally accepting the original exception) that Resilience4j invokes when the call is short-circuited or throws. Spring Boot auto-configures the underlying registry when the resilience4j-spring-boot2 / resilience4j-spring-boot3 starter is on the classpath.

In the Spring bean lifecycle, @PostConstruct is invoked during the BeanPostProcessor phase. Fill in the two blanks: a @PostConstruct method executes _____ all dependencies have been injected, and _____ InitializingBean.afterPropertiesSet() is called. (For each blank, write a single word: either 'before' or 'after'.)#

Show answer

In the Spring bean lifecycle, @PostConstruct is invoked during the BeanPostProcessor phase. Fill in the two blanks: a @PostConstruct method executes after all dependencies have been injected, and before InitializingBean.afterPropertiesSet() is called. (For each blank, write a single word: either 'before' or 'after'.)

Why:

Spring fully completes dependency injection (field and setter injection via @Autowired) before any initialization callbacks fire. @PostConstruct is triggered by CommonAnnotationBeanPostProcessor.postProcessBeforeInitialization, which runs after injection but before the InitializingBean.afterPropertiesSet() callback and any custom init-method.

A prototype-scoped bean is injected (via @Autowired constructor injection) into a singleton-scoped bean in a Spring Boot application. How many times is the prototype bean instantiated during the lifetime of that singleton? If you need a fresh prototype instance on every method call rather than the one captured at singleton-creation time, name the Spring annotation (method-injection) you would use instead.#

Show answer

The prototype bean is instantiated only once — at the time the singleton is created and its dependencies are wired. Spring does not re-inject prototype beans into singletons on each use. To obtain a new prototype instance on every call, annotate an abstract or concrete method returning the prototype type with @Lookup; Spring overrides the method with a CGLIB proxy that calls getBean() each time.

Why:

When a prototype bean is injected into a singleton at wiring time, Spring creates the prototype instance once and caches the reference in the singleton — it is never recreated for subsequent calls. @Lookup (a form of method injection) solves this: Spring generates a CGLIB subclass that overrides the annotated method to return a fresh prototype bean from the context on each invocation.

In Spring Boot, consider the following statements about built-in bean scopes and their lifecycle management. Which of them are TRUE? (Select all that apply.)#

Options

Pick every one that applies.

Show answer

Singleton beans are eagerly created at refresh by default; prototype beans are created on every request from the container; request-scoped beans need a web-aware ApplicationContext. The container does not call @PreDestroy on prototype beans when the context closes — it only creates and configures prototypes, then hands them off, so their destruction callbacks are never invoked.

Why:

Singleton beans are eagerly instantiated at refresh time unless annotated with @Lazy, so the statement that singleton-scoped beans are eagerly instantiated by default when the ApplicationContext is refreshed is true. Prototype-scoped beans are instantiated on every call to getBean or injection, so the statement that prototype-scoped beans are created each time they are requested from the container is true. The container does NOT manage the full lifecycle of prototype beans — it creates, configures, and hands them off but never calls @PreDestroy or destroy methods on them, so the statement that the container calls @PreDestroy lifecycle methods on prototype-scoped beans when the ApplicationContext is closed is false. Request-scoped (and session-scoped) beans are web-specific and require a web-aware ApplicationContext, so the statement that request-scoped beans require a web-aware ApplicationContext is true.

Which of the following statements about Spring's dependency injection mechanisms are TRUE? (Select all that apply.)#

Options

Pick every one that applies.

Show answer

Constructor injection lets you mark dependencies final; @Qualifier combined with @Autowired disambiguates multiple same-type beans; and field injection uses reflection with no setter or constructor parameter needed. @Autowired does not always throw NoUniqueBeanDefinitionException when duplicates exist — it first tries to match by name. Setter injection is not recommended for mandatory dependencies; constructor injection is, because it enforces them at construction time.

Why:

Constructor injection sets dependencies before the object is fully constructed, so fields can be marked final — the statement about constructor injection allowing final fields is true. When multiple candidates of the same type exist, @Autowired does NOT always throw; it attempts to narrow by matching the field/parameter name to a bean name before failing, so the claim that field injection with @Autowired will always throw NoUniqueBeanDefinitionException is false. @Qualifier explicitly narrows the candidate set and can be used alongside @Autowired — the statement about combining @Qualifier with @Autowired is true. Field injection uses reflection to set private fields directly, with no setter or constructor parameter required — the statement about field injection using reflection without requiring a setter or constructor parameter is true. Constructor injection (not setter injection) is the recommended approach for mandatory dependencies, because it enforces them at construction time and allows immutability — the claim that setter injection is recommended for mandatory dependencies is false.

Below is a Spring Boot 3.x application snippet. All classes are in the component-scan path and the application context starts successfully. Annotations used: @Component (org.springframework.stereotype.Component), @Autowired (org.springframework.beans.factory.annotation.Autowired), and @PostConstruct (jakarta.annotation.PostConstruct). What is printed to stdout when the application context fully starts?#

@Component
class Printer {
    Printer() { System.out.println("Printer created"); }
}

@Component
class Worker {
    @Autowired
    private Printer printer;

    Worker() {
        System.out.println("Worker constructor: printer=" +
            (printer != null ? "injected" : "null"));
    }

    @PostConstruct
    void onStart() {
        System.out.println("Worker onStart: printer=" +
            (printer != null ? "injected" : "null"));
    }
}
Show answer
Printer created
Worker constructor: printer=null
Worker onStart: printer=injected
Why:

With field injection, Spring's bean lifecycle proceeds in three phases: (1) instantiate the bean by calling its no-arg constructor, (2) inject dependencies into fields, then (3) call @PostConstruct. When Spring creates Worker, it first calls the constructor — at that point @Autowired fields are still null, so 'Worker constructor: printer=null' is printed. After construction, Spring injects the Printer bean (which it creates first, printing 'Printer created'), then calls onStart(), where printer is now non-null. The complete output is:

Printer created Worker constructor: printer=null Worker onStart: printer=injected

In Spring Boot, a singleton-scoped bean has a @Autowired reference to a prototype-scoped bean. Why does the prototype instance effectively become "frozen" after the singleton is created, and what are the two idiomatic ways to ensure a fresh prototype instance is obtained on each use?#

Show answer

When a singleton collaborates with a prototype through a plain @Autowired field, Spring injects the prototype once at singleton-creation time and the singleton permanently holds that single reference — the prototype's scope is never re-consulted thereafter.

To get a new prototype on each access you can:

  1. Inject an ObjectProvider<T> or Provider<T> (JSR-330 javax.inject.Provider) and call getObject() / get() each time you need a fresh instance. This is the lightweight, recommended approach.

  2. Use a scoped-proxy: annotate the prototype bean with @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) (or INTERFACES if it has an interface). Spring injects a CGLIB/JDK proxy; each method invocation on the proxy delegates to a freshly resolved prototype instance. Alternatively use @Lookup on a method returning the prototype type so Spring overrides it to return a new prototype each call.

Why:

This tests senior-level understanding that scope only governs creation, not re-injection. The singleton is created once, so its prototype collaborator is resolved once. The two solutions — ObjectProvider/Provider injection vs scoped-proxy or @Lookup method override — are the canonical Spring mechanisms for breaking this stale-reference problem.

In the Spring IoC container lifecycle, what is the precise ordering difference between BeanFactoryPostProcessor and BeanPostProcessor, and why does it mean that a BeanFactoryPostProcessor must be registered eagerly (not discovered through component-scanning of a regular @Configuration)?#

Show answer

Ordering: BeanFactoryPostProcessor beans are instantiated and invoked immediately after the bean definitions are loaded but before any regular bean is instantiated — they operate on the BeanDefinition metadata (e.g. PropertySourcesPlaceholderConfigurer resolves ${...} in definitions). BeanPostProcessor beans are instantiated early but their postProcessBeforeInitialization / postProcessAfterInitialization callbacks run around each regular bean's initialization phase (before/after @PostConstruct, InitializingBean.afterPropertiesSet, and init-method).

Why eager registration matters: Because BeanFactoryPostProcessor must run before regular beans are created, Spring needs to detect them very early in refresh(). If a BeanFactoryPostProcessor were only discoverable through component-scanning of a regular @Configuration, it might itself depend on beans that have not yet been processed, and the container could not guarantee ordering. Therefore Spring treats BeanFactoryPostProcessor as infrastructure: it is detected and instantiated outside the normal bean lifecycle, and AOP auto-proxying (a BeanPostProcessor) is deliberately disabled for these early beans to avoid premature proxying.

Why:

This tests the distinction between the two extension points at the definition vs instance level, and the infrastructure-first bootstrapping constraint that Spring enforces for BeanFactoryPostProcessor — a senior-level lifecycle detail that explains why placeholder configurers and similar processors behave differently from regular @PostConstruct-style callbacks.

Why does Spring not call @PreDestroy (or DisposableBean.destroy() / destroy-method) on prototype-scoped beans, and what practical implication does this have for resource cleanup when using prototype scope?#

Show answer

Spring's container only manages the complete lifecycle (creation → initialization → destruction) of singleton-scoped beans. For prototype beans, the container creates and initializes the instance, then hands it off to the caller and retains no reference to it. Because the container no longer tracks the instance, it cannot know when the prototype goes out of scope and therefore never invokes destruction callbacks.

Practical implication: The client code that receives a prototype bean is solely responsible for releasing any resources it holds (closing files, connections, etc.). If the prototype bean needs deterministic cleanup, the caller must manage it — e.g. by calling a close method manually, wrapping usage in a try-with-resources (if the bean implements AutoCloseable), or by registering the instance with an external lifecycle manager. Relying on container-managed destruction for a prototype will silently leak resources.

Why:

This tests a frequently-misunderstood lifecycle asymmetry: the container's responsibility for a prototype ends at hand-off. Seniors must know that destruction callbacks are singleton-only by design, and that the ownership of cleanup transfers to the client — a common source of resource leaks when prototype scope is chosen naively.

A Spring singleton bean class MyService is annotated with @PostConstruct on a method init(), implements InitializingBean (providing afterPropertiesSet()), and is registered via @Bean(initMethod = "customInit"). Considering Spring Framework 6.x / Spring Boot 3.x default behavior, which of the following statements are TRUE?#

Options

Pick every one that applies.

Show answer

When a single Spring bean has all three initialization mechanisms — @PostConstruct, InitializingBean.afterPropertiesSet(), and a @Bean(initMethod = ...) — Spring calls them in that exact order: @PostConstruct first, then afterPropertiesSet(), then the custom init method. None is skipped, and all run after dependency injection is complete, not before.

Why:

Spring invokes bean lifecycle initialization callbacks in a fixed order: first @PostConstruct (JSR-250), then InitializingBean.afterPropertiesSet(), and finally the custom init method named in @Bean(initMethod = ...). All three are called if all three are present — Spring does not skip any of them, so the claim that Spring skips the custom initMethod when the bean implements InitializingBean is false. The claim that @PostConstruct is invoked before setter-based dependency injection is false because all initialization callbacks run only after dependency injection (both constructor and setter/field injection) is fully complete, not before it. The statement that @PostConstruct is invoked before afterPropertiesSet() is true because @PostConstruct always precedes afterPropertiesSet(). The statement that the custom init method declared via @Bean(initMethod = "customInit") is invoked after afterPropertiesSet() is true because the custom initMethod always runs last in the sequence, after afterPropertiesSet().

Given the following Spring Boot 3.x application (all classes are component-scanned; no circular dependencies exist), what exact text does the System.out.println in the CommandLineRunner.run method print to stdout?#

// Spring Boot 3.x — all classes are @Component-scanned; no circular dependencies exist.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class DemoApp implements CommandLineRunner {
    @Autowired
    private Foo foo;

    public static void main(String[] args) {
        SpringApplication.run(DemoApp.class, args);
    }

    @Override
    public void run(String... args) {
        System.out.println(foo.getValue());
    }
}

@Component
class Foo {
    @Autowired
    private Bar bar;

    private final String value;

    public Foo() {
        this.value = (bar != null) ? bar.getName() : "none";
    }

    public String getValue() {
        return value + ":" + (bar != null ? bar.getName() : "null");
    }
}

@Component
class Bar {
    String getName() { return "bar"; }
}
Show answer
none:bar
Why:

Foo uses field injection for bar (@Autowired on the field). Spring constructs the Foo instance first by calling its no-arg constructor — at that point field injection has NOT yet occurred, so bar is null. The constructor therefore sets value = "none". After construction completes, Spring injects bar via reflection. When run() calls foo.getValue(), the expression evaluates to value + ":" + bar.getName() = "none" + ":" + "bar" = "none:bar". This illustrates the core disadvantage of field injection: the dependency is unavailable during construction, so any logic in the constructor that needs it silently sees null.

In Spring's default singleton bean lifecycle, a circular dependency between two singleton beans can be resolved automatically when the beans use setter or field injection, because Spring exposes an early reference to the partially-initialized bean from its singletonFactories cache during property population. If both beans use constructor injection instead, this mechanism cannot apply because the object cannot be referenced before the constructor returns, and Spring throws BeanCurrentlyInCreationException unless a @Lazy annotation on a constructor parameter injects a proxy to break the cycle.#

Options

Show answer

True. Spring resolves setter/field-injection circular dependencies by exposing an early, partially-initialized reference from its singletonFactories cache during property population. With constructor injection, no instance exists before the constructor returns, so there is nothing to expose; Spring throws BeanCurrentlyInCreationException unless @Lazy on a constructor parameter injects a proxy that defers real creation and breaks the cycle.

Why:

Setter/field-injection circular dependencies are resolved via Spring's three-level singleton cache: when bean A is being created, an ObjectFactory that can return A's early reference is stored in singletonFactories before A's properties are populated. When B (which A depends on) is then created and tries to inject A, it retrieves A's early reference from that cache, breaking the cycle. With constructor injection, the instance does not exist until the constructor returns, so there is nothing to expose as an early reference, and Spring detects the unresolvable cycle and throws BeanCurrentlyInCreationException. Annotating a constructor parameter with @Lazy causes Spring to inject a proxy stub instead of eagerly creating the real bean, which defers actual creation and breaks the cycle.

Assume AuditLogger and PaymentGateway are singleton beans correctly registered in the Spring context. The application fails to start with a NullPointerException. Which line is the root cause of the bug?#

@Service
public class OrderProcessor {

    @Autowired
    private AuditLogger auditLogger;

    private final PaymentGateway paymentGateway;

    public OrderProcessor(PaymentGateway paymentGateway) {
        this.paymentGateway = paymentGateway;
        auditLogger.log("OrderProcessor created");
    }
}
Show answer

The bug is on line 11.

Why:

Spring resolves the single constructor of OrderProcessor automatically (Spring 4.3+), instantiates the bean, and only THEN performs field injection via AutowiredAnnotationBeanPostProcessor. During constructor execution the auditLogger field is still null, so the call on line 11 throws an NPE. The paymentGateway is safe because it is constructor-injected. The fix is to move auditLogger into the constructor (preferred for final-field immutability) or relocate the log call to a @PostConstruct method, which runs after both constructor and field injection are complete.

Related interview questions

Job market

See spring-boot salaries and hiring demand from live job postings.

The other 198 questions

This page shows 25 and marks what you pick. That's as far as a page can go. A free account opens the other 198 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.

Start with this topic

Free · the whole bank · 100 marked answers per 30 days · written feedback on the paid plan

Interview booked? Practise the job ad instead

What moved, monthly

One email a month when the bulletin comes out: what moved in the markets we track, and the new question topics we published. Confirm your address to join. Unsubscribe any time.