Skip to main content
PProfileMatch

Spring Boot Interview Questions and Answers

27 questions8 beginner · 13 intermediate · 6 advancedLast reviewed

This set is for Java developers preparing for backend roles that use Spring Boot, from first jobs to experienced engineers who are asked about transactions, JPA performance and production behaviour. Where versions matter the answers assume Spring Boot 3.x, which needs Java 17 or newer. Core language questions live in the Java interview set.

Practise by reading only the question, saying your answer aloud in about a minute, and then checking it against the model answer and the "what they are checking" line. Interviewers usually follow with "what happens under the hood", so try to explain the mechanism, not only the annotation. The Spring Boot course and the REST API course cover the same ground with hands-on projects.

  1. 1What is Spring Boot, and how is it different from the Spring Framework?Beginner

    The Spring Framework is the core toolkit: dependency injection, AOP, transactions, MVC and data access. It is powerful but historically needed a lot of explicit configuration. Spring Boot sits on top of it and removes that setup work by providing opinionated defaults.

    Boot gives you starter dependencies, auto-configuration that wires beans based on what is on the classpath, externalised configuration, an embedded server such as Tomcat so the app runs as a plain executable jar, and production features like Actuator. You are still using Spring underneath; Boot decides sensible defaults and gets out of the way when you define your own beans.

    In short: Spring is the engine, Boot is the pre-assembled car.

    What the interviewer is checking: Whether you can separate the framework from the convenience layer and name concrete things Boot adds.

    Likely follow-up: Can you use Spring without Boot, and when would you?

  2. 2What does @SpringBootApplication actually do?Beginner

    It is a convenience annotation that combines three others. @SpringBootConfiguration marks the class as a configuration source, so it can declare @Bean methods. @EnableAutoConfiguration turns on Boot's auto-configuration. @ComponentScan scans the class's own package and all sub-packages for components such as @Component, @Service and @RestController.

    The scanning detail causes a common bug. If the main class sits in a deep package, or your beans live in a sibling package, they are never found and you get a "no qualifying bean" error. Keep the main class in the root package of the application, or list the base packages explicitly.

    What the interviewer is checking: Knowledge of the three meta-annotations and the component-scan boundary.

    Likely follow-up: How would you exclude one specific auto-configuration class?

  3. 3What are Spring Boot starters, and why do they exist?Beginner

    A starter is a dependency descriptor that pulls in a curated, compatible set of libraries for one purpose. For example, spring-boot-starter-web brings Spring MVC, Jackson and an embedded Tomcat, and spring-boot-starter-data-jpa brings Hibernate and Spring Data JPA.

    They solve two problems: you do not hunt for the right list of artifacts, and you do not manage version compatibility between them, because Boot's parent POM or BOM fixes the versions. A starter has no code of its own to speak of; it works together with auto-configuration, which notices the libraries and configures them.

    You can override a managed version if you really need to, but doing so takes on the compatibility risk yourself.

    What the interviewer is checking: That you see starters and auto-configuration as two halves of the same mechanism.

    Likely follow-up: How do you swap Tomcat for Jetty in a web application?

  4. 4Why is constructor injection preferred over field injection?Beginner

    Dependency injection means a class receives its collaborators from the container instead of creating them. With constructor injection the dependencies are parameters, so the object can never exist half-wired. They can be final, which makes the class easier to reason about, and the class can be unit tested with plain new and mocks, with no Spring context.

    Field injection with @Autowired hides dependencies, forces reflection to test, and lets you accumulate a dozen dependencies without noticing. A long constructor is a useful warning that the class does too much.

    Since Spring 4.3, a class with a single constructor needs no @Autowired at all.

    java
    @Service
    public class AppointmentService {
    
        private final SlotRepository slots;
        private final NotificationClient notifier;
    
        public AppointmentService(SlotRepository slots, NotificationClient notifier) {
            this.slots = slots;
            this.notifier = notifier;
        }
    }

    What the interviewer is checking: Testability and design reasoning rather than "it is best practice".

    Likely follow-up: When is setter injection still reasonable?

  5. 5What is the difference between @Component, @Service, @Repository and @Controller?Beginner

    All four are stereotype annotations that register a class as a Spring bean during component scanning. @Component is the generic one; the others are specialisations that communicate the role of the class.

    @Service marks business logic and adds no behaviour. @Controller marks a web layer class, and @RestController adds @ResponseBody, so return values are written to the response body. @Repository marks the data layer and has one real effect: exception translation, where persistence exceptions are converted into Spring's DataAccessException hierarchy.

    Technically you could use @Component for everything, but the specific annotations make the layers readable, let tooling and AOP target them, and let you write pointcuts by layer.

    What the interviewer is checking: Whether you know that only some stereotypes add behaviour.

    Likely follow-up: How does Spring decide which implementation to inject when two beans share an interface?

  6. 6What bean scopes does Spring support, and what happens if a prototype bean is injected into a singleton?Beginner

    The default is singleton: one instance per application context, shared by every caller, so it must be stateless or thread-safe. prototype creates a new instance each time it is requested. In a web application there are also request, session, application and websocket scopes.

    A singleton gets its dependencies injected once, at creation. If you inject a prototype bean into it, the singleton keeps that single instance forever, so you do not actually get a fresh object per use. To get a new one each time, inject an ObjectProvider<T> and call getObject(), or use a scoped proxy.

    Most beans should stay singletons; mutable per-user state belongs in a request object or session, not a field of a service.

    What the interviewer is checking: Knowledge of scope-mismatch behaviour and the thread-safety implication of singletons.

    Likely follow-up: Why is a mutable field on a singleton controller a bug waiting to happen?

  7. 7How do you build a simple REST endpoint, and what do @PathVariable, @RequestParam and @RequestBody bind?Beginner

    Annotate a class with @RestController, add a base @RequestMapping, and use @GetMapping, @PostMapping and friends on methods. Return an object, and Jackson serialises it to JSON.

    @PathVariable binds a segment of the URL path, like the id in /clinics/7/slots. @RequestParam binds a query string or form parameter, such as ?date=2025-03-01. @RequestBody deserialises the JSON request body into an object. Wrap the return in ResponseEntity when you need to control the status code or headers, for example 201 with a Location header on creation.

    Keep controllers thin: parse the request, call a service, shape the response.

    java
    @RestController
    @RequestMapping("/clinics/{clinicId}/slots")
    public class SlotController {
    
        private final SlotService service;
    
        public SlotController(SlotService service) { this.service = service; }
    
        @GetMapping
        public List<SlotDto> list(@PathVariable Long clinicId,
                                  @RequestParam LocalDate date) {
            return service.freeSlots(clinicId, date);
        }
    
        @PostMapping
        public ResponseEntity<SlotDto> create(@PathVariable Long clinicId,
                                              @RequestBody @Valid CreateSlotRequest req) {
            SlotDto saved = service.create(clinicId, req);
            return ResponseEntity.status(HttpStatus.CREATED).body(saved);
        }
    }

    What the interviewer is checking: Fluency with the everyday annotations and awareness of correct status codes.

    Likely follow-up: What is the difference between @Controller and @RestController?

  8. 8How do application.properties, application.yml and profiles work together?Beginner

    Boot loads configuration from application.properties or application.yml on the classpath. Both formats map to the same keys; YAML is just a nested syntax. A profile gives you environment-specific overrides: set spring.profiles.active=prod, and application-prod.yml is layered on top of the base file.

    Values can also come from environment variables, command-line arguments and external config files, which take priority over files packaged inside the jar. That ordering is what lets you build one artifact and promote it unchanged from test to production, supplying only the database URL and secrets from outside.

    Never commit secrets into these files; read them from the environment or a secret manager.

    What the interviewer is checking: Understanding of externalised configuration and the build-once, configure-per-environment idea.

    Likely follow-up: How would you make a bean exist only in the dev profile?

  9. 9When do you use @Component and when @Bean?Intermediate

    @Component goes on a class you own; component scanning detects it and creates the bean. @Bean goes on a method inside a @Configuration class and registers whatever the method returns. Use @Bean for classes you cannot annotate, such as a third-party ObjectMapper or RestClient, or when creating the object needs custom logic or conditions.

    A subtle difference: in a @Configuration class, which Spring proxies by default, calling one @Bean method from another returns the same singleton instead of constructing a second object. In a plain @Component class that interception does not happen, so such calls just create new instances.

    Rule: scanning for your own classes, @Bean for external types and explicit wiring.

    java
    @Configuration
    public class HttpConfig {
    
        @Bean
        public RestClient pricingClient(RestClient.Builder builder,
                                        @Value("${pricing.base-url}") String baseUrl) {
            return builder.baseUrl(baseUrl).build();
        }
    }

    What the interviewer is checking: Whether you understand explicit versus scanned registration, not only that both create beans.

    Likely follow-up: What does proxyBeanMethods = false change, and when is it worth using?

  10. 10How does Spring Boot auto-configuration decide what to set up?Intermediate

    Libraries ship auto-configuration classes, and Boot discovers them through a list file inside each jar (in Boot 3 this is META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports). @EnableAutoConfiguration loads those classes, but each one is guarded by conditions such as @ConditionalOnClass, @ConditionalOnProperty and @ConditionalOnMissingBean.

    For example, the DataSource configuration activates only when a database driver is on the classpath and you have not defined your own DataSource. That last condition is the key design rule: auto-configuration backs off whenever you declare your own bean, so your explicit configuration always wins.

    To see what was applied and why, start with --debug or open the Actuator conditions endpoint, which reports matched and unmatched conditions.

    What the interviewer is checking: Mechanical understanding of conditions and back-off behaviour instead of "it is magic".

    Likely follow-up: How would you write your own auto-configuration for a shared internal library?

  11. 11What changed when moving from Spring Boot 2 to 3, and what usually breaks first?Intermediate

    Boot 3 builds on Spring Framework 6 and requires Java 17 or newer. The most visible change is the move from javax.* to jakarta.* packages for servlet, persistence and validation APIs, so imports like javax.persistence.Entity become jakarta.persistence.Entity. Hibernate 6 and Spring Security 6 come with it.

    What breaks first: those imports, third-party libraries that still use javax, security configuration written around the removed WebSecurityConfigurerAdapter (it is replaced by a SecurityFilterChain bean), and some Hibernate query behaviour changes. Boot 3 also adds improved observability through Micrometer and support for compiling to a native image.

    The safe path is to upgrade to the latest 2.7 first, fix deprecation warnings, then move to 3.x.

    What the interviewer is checking: Practical migration experience and awareness of the jakarta namespace change.

    Likely follow-up: How would you handle a dependency that has not moved to jakarta yet?

  12. 12How do you validate request input and return clean 400 responses?Intermediate

    Add spring-boot-starter-validation, annotate the request class with Bean Validation constraints such as @NotBlank, @Email, @Size or @Positive, and put @Valid on the @RequestBody parameter. If validation fails, Spring throws MethodArgumentNotValidException before your controller code runs, which maps to HTTP 400.

    The default error body is noisy, so handle that exception in a @RestControllerAdvice and return field-level messages. For checks that need data, such as "slot not already booked", do those in the service layer, because annotations validate shape, not business state.

    Validate at the boundary and keep entities free from request-specific rules; use a separate request DTO per use case.

    java
    public record BookingRequest(
            @NotNull Long slotId,
            @NotBlank @Size(max = 80) String patientName,
            @Email String contactEmail) {
    }

    What the interviewer is checking: Knowing where validation belongs and the difference between format checks and business rules.

    Likely follow-up: How do you validate @RequestParam or @PathVariable values, not only request bodies?

  13. 13How do you handle exceptions globally and return a consistent error format?Intermediate

    Create a class annotated with @RestControllerAdvice and add @ExceptionHandler methods, each mapping an exception type to a status code and body. It applies across all controllers, so error handling does not repeat in each one.

    Define your own domain exceptions, for example SlotAlreadyBookedException mapped to 409, rather than leaking IllegalStateException messages. Spring 6 adds the ProblemDetail type, which gives a standard problem-details JSON shape for errors, so clients get a predictable structure.

    Log server-side errors with a correlation id and return a generic message to the client; never return stack traces or SQL errors. Handle the most specific exceptions first and keep one fallback for unexpected ones.

    java
    @RestControllerAdvice
    public class ApiExceptionHandler {
    
        @ExceptionHandler(SlotAlreadyBookedException.class)
        public ProblemDetail onConflict(SlotAlreadyBookedException ex) {
            ProblemDetail pd = ProblemDetail.forStatusAndDetail(HttpStatus.CONFLICT, ex.getMessage());
            pd.setTitle("Slot unavailable");
            return pd;
        }
    }

    What the interviewer is checking: Clean error-handling design and awareness of what must not leak to clients.

    Likely follow-up: How do you test that handler without starting the whole application?

  14. 14Compare @Value and @ConfigurationProperties. Which do you prefer for a group of settings?Intermediate

    @Value injects a single property, which is fine for one-off values. @ConfigurationProperties binds a whole prefix, such as booking.*, into a typed object. I prefer it for groups of related settings.

    It gives relaxed binding (max-retries, maxRetries and MAX_RETRIES all map), type conversion for durations and lists, nested structures, IDE metadata, and validation by adding @Validated with constraints, so a bad configuration fails at startup rather than at the first request. In Boot 3 a record with a single constructor binds without extra annotations, though you still need to register the class, for example with @ConfigurationPropertiesScan.

    @Value does support SpEL, which is its one advantage.

    java
    @ConfigurationProperties(prefix = "booking")
    @Validated
    public record BookingProperties(
            @Min(1) int maxDaysAhead,
            @NotNull Duration holdTime,
            List<String> blockedDates) {
    }

    What the interviewer is checking: Preference backed by concrete benefits, including fail-fast validation.

    Likely follow-up: In what order do command-line arguments, environment variables and application.yml override each other?

  15. 15What is Spring Boot Actuator, and what would you expose in production?Intermediate

    Actuator adds production-ready endpoints that expose the application's state: health, info, metrics, loggers, env, threaddump, heapdump and more. Metrics come through Micrometer, which can feed systems such as Prometheus.

    By default only health is exposed over HTTP, and you widen that with management.endpoints.web.exposure.include. I would expose health, info and metrics, plus the liveness and readiness health groups if running on Kubernetes, and keep the sensitive ones such as env, heapdump and loggers off the public network.

    Secure the management endpoints behind authentication, or run them on a separate management port reachable only internally. Also be careful that health details do not reveal connection strings.

    What the interviewer is checking: Operational maturity and security awareness, not only knowing the endpoint names.

    Likely follow-up: How would you add a custom health indicator for a downstream payment API?

  16. 16How does @Transactional work, and when does it roll back?Intermediate

    Spring wraps the bean in a proxy. When a transactional method is called through the proxy, it begins a transaction (or joins the existing one, since the default propagation is REQUIRED), runs your method, and commits on success.

    The default rollback rule surprises people: it rolls back for unchecked exceptions (RuntimeException and Error) but commits for checked exceptions. To roll back on a checked one, use @Transactional(rollbackFor = Exception.class).

    Two more pitfalls: if you catch the exception inside the method and do not rethrow, the proxy sees a normal return and commits. And if an inner REQUIRED method throws and marks the transaction rollback-only, an outer method that swallows that exception still ends with an UnexpectedRollbackException.

    What the interviewer is checking: Whether you know the proxy mechanism and the default rollback rules.

    Likely follow-up: What does readOnly = true actually do?

  17. 17Why does a @Transactional method sometimes behave as if the annotation is not there?Intermediate

    Because the transaction logic lives in the proxy, not in your class. When another bean calls your method, it goes through the proxy and the transaction starts. When a method in the same class calls another method on this, it bypasses the proxy, so the second method's annotation is ignored. This is the self-invocation problem, and it equally affects @Async and @Cacheable.

    Other causes: the method is private, or final in a class that needs a subclass proxy, or the bean was created with new instead of by Spring.

    Fixes: move the method to another bean, which is usually the cleanest design; or use TransactionTemplate for programmatic control; or inject the proxy into itself, which works but is a smell.

    java
    @Service
    public class RefundService {
    
        public void processBatch(List<Long> ids) {
            for (Long id : ids) {
                refundOne(id);          // internal call: bypasses the proxy, no new transaction
            }
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void refundOne(Long id) {
            // intended to run in its own transaction per refund
        }
    }

    What the interviewer is checking: Understanding of proxy-based AOP, which explains a whole family of Spring bugs.

    Likely follow-up: How would you restructure this so each refund really runs in its own transaction?

  18. 18Why shouldn't you return JPA entities directly from a controller? When do you use DTOs?Intermediate

    An entity models a table and is tied to a persistence context. Returning it directly couples your public API to your schema: add a column and the JSON changes, expose a field like a password hash by accident, or hit infinite recursion on bidirectional relationships. Serialising a lazy association outside a transaction can also throw a lazy-loading error or trigger hidden queries.

    A DTO is a plain object shaped for one use case. It lets the API evolve separately from the database, controls exactly which fields leave the system, and for read endpoints can be filled straight from a query projection, avoiding loading whole entities.

    The cost is mapping code, which you can reduce with records and a mapper library. Request DTOs also stop clients from setting fields such as id or role by mass assignment.

    What the interviewer is checking: Layering discipline and awareness of security and performance consequences.

    Likely follow-up: How would you fill a DTO directly from a Spring Data query?

  19. 19What is lazy loading, and why do you get LazyInitializationException?Intermediate

    With lazy loading, Hibernate does not fetch an association until you access it. A lazy field holds a proxy or a collection wrapper, and the first access triggers a query. That only works while the persistence context, i.e. the session, is still open.

    LazyInitializationException occurs when you touch the association after the session has closed, typically after the transactional service method returned and you access appointment.getPatient().getName() in the controller or during serialisation. Defaults matter: @OneToMany is lazy, but @ManyToOne and @OneToOne are eager.

    The right fix is to load what you need inside the service, with a fetch join, an entity graph or a DTO projection. Making everything eager is the wrong fix. Spring Boot's open-in-view setting, on by default, hides the exception but keeps a connection open during view rendering, so many teams turn it off.

    What the interviewer is checking: Whether you understand the session boundary and avoid fixing symptoms with eager fetching.

    Likely follow-up: What are the trade-offs of keeping open-in-view enabled?

  20. 20What is the N+1 query problem in JPA, how do you spot it, and how do you fix it?Intermediate

    You run one query to load N parents, then lazy access to each parent's association fires one extra query per parent, giving N+1 round trips. Loading 200 orders and printing their line items quietly turns into 201 queries.

    Spot it by turning on SQL logging or Hibernate statistics in a test and counting statements, or from slow endpoints that scale with result size.

    Fixes: a JOIN FETCH query or @EntityGraph to load parents and children together; batch fetching (@BatchSize or Hibernate's default batch fetch size) to load children for many parents in a few queries; or a DTO projection that selects only needed columns. Beware that fetch-joining a collection together with pagination makes Hibernate page in memory, so for paged lists fetch the page of ids first, or use batching.

    java
    public interface OrderRepository extends JpaRepository<Order, Long> {
    
        // Without this, order.getLines() inside a loop fires one query per order
        @Query("select distinct o from Order o join fetch o.lines where o.status = :status")
        List<Order> findWithLines(@Param("status") OrderStatus status);
    }

    What the interviewer is checking: Practical JPA performance skill: detection and several remedies with their limits.

    Likely follow-up: Why can join fetch on two collections at once cause trouble?

  21. 21Which test slices does Spring Boot offer, and when do you use @SpringBootTest instead?Intermediate

    Slices load only part of the context, which makes tests fast. @WebMvcTest loads the web layer, controllers, advice and JSON conversion, and you supply the services as mocks. @DataJpaTest loads repositories and an in-memory database by default, and rolls back after each test. There are also slices for JSON and for REST clients.

    @SpringBootTest starts the whole application context, so it is slower, and I reserve it for a few integration tests that prove the wiring, configuration and security work end to end. For repository tests that depend on database-specific SQL, use Testcontainers with the real database engine instead of H2.

    Pure unit tests with no Spring at all are the fastest, and constructor injection makes them easy.

    java
    @WebMvcTest(SlotController.class)
    class SlotControllerTest {
    
        @Autowired MockMvc mvc;
        @MockitoBean SlotService service;   // @MockBean in older 3.x releases
    
        @Test
        void returnsFreeSlots() throws Exception {
            when(service.freeSlots(7L, LocalDate.of(2025, 3, 1))).thenReturn(List.of());
    
            mvc.perform(get("/clinics/7/slots").param("date", "2025-03-01"))
               .andExpect(status().isOk());
        }
    }

    What the interviewer is checking: A sensible test pyramid and knowledge of what each annotation loads.

    Likely follow-up: Why can an H2-based repository test pass while production fails?

  22. 22How do you secure a Spring Boot 3 REST API? Outline the configuration and its defaults.Advanced

    Adding Spring Security locks everything down by default, with basic or form login and a generated password. In Spring Security 6 you configure it by declaring a SecurityFilterChain bean using the lambda DSL, since WebSecurityConfigurerAdapter is gone. Use authorizeHttpRequests with requestMatchers for URL rules, and method security such as @PreAuthorize for finer checks.

    For a stateless API, use token authentication, either a JWT validated by the resource-server support or opaque tokens, and set session creation to stateless. Store passwords with BCryptPasswordEncoder or the delegating encoder. CSRF protection is on by default; it is reasonable to disable it only for APIs that authenticate with headers rather than cookies.

    Add CORS rules deliberately, and never trust client-supplied roles. The JWT authentication course covers token handling in depth.

    java
    @Configuration
    @EnableMethodSecurity
    public class SecurityConfig {
    
        @Bean
        SecurityFilterChain api(HttpSecurity http) throws Exception {
            http
                .csrf(csrf -> csrf.disable())     // stateless, header-token API only
                .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/actuator/health").permitAll()
                    .requestMatchers(HttpMethod.GET, "/clinics/**").hasAnyRole("PATIENT", "STAFF")
                    .anyRequest().authenticated())
                .oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()));
            return http.build();
        }
    }

    What the interviewer is checking: Up-to-date security configuration knowledge and the reasoning behind each choice, especially CSRF.

    Likely follow-up: How does the security filter chain relate to servlet filters and the DispatcherServlet?

  23. 23Explain REQUIRED versus REQUIRES_NEW propagation. When is REQUIRES_NEW dangerous?Advanced

    REQUIRED, the default, joins an existing transaction or starts one if none exists, so the outer and inner methods commit or roll back together. REQUIRES_NEW suspends the current transaction and starts an independent one on a separate database connection, committing or rolling back on its own.

    It is useful for work that must persist even if the caller fails, like writing an audit record or a failed-attempt counter.

    The dangers: it needs a second connection while the first is held, so under load a small pool can be exhausted with every thread waiting for a connection it cannot get, a deadlock of sorts. The new transaction cannot see uncommitted changes from the suspended one, and it can block on rows the outer transaction has locked. Also remember it only works when the call crosses a proxy boundary. Use it sparingly and keep those inner transactions short.

    What the interviewer is checking: Depth beyond definitions: connection-pool consequences and visibility rules.

    Likely follow-up: How does the isolation level interact with this, and what is the database default you rely on?

  24. 24Two users book the last slot at the same moment. How do you prevent a double booking with JPA?Advanced

    A check-then-insert in application code is a race: both transactions read "free" and both write. There are three layers of defence.

    First, a database unique constraint on the slot id, which is the only truly reliable guard; the loser gets a constraint violation that you translate to a 409. Second, optimistic locking: add a @Version field to the slot entity, and Hibernate includes the version in the update's where clause, so the second writer updates zero rows and gets an optimistic-locking exception to retry or report. Third, pessimistic locking with @Lock(PESSIMISTIC_WRITE) or select ... for update, which blocks the second user, useful when conflicts are frequent.

    Optimistic locking suits low contention; pessimistic suits hot rows. Either way, the database is the final arbiter.

    java
    @Entity
    public class Slot {
        @Id @GeneratedValue
        private Long id;
    
        @Version
        private long version;      // incremented on every update; stale writers fail
    
        private boolean booked;
        // getters / setters omitted
    }

    What the interviewer is checking: Concurrency design with data stores, and whether you trust the database instead of in-memory checks.

    Likely follow-up: How would you retry on optimistic-lock failure without retrying on real business errors?

  25. 25How does Spring create proxies for AOP, and what limits does that impose?Advanced

    Cross-cutting features such as @Transactional, @Async, @Cacheable and method security are applied by wrapping the target bean in a proxy that runs extra logic before and after the real call. Spring can use a JDK dynamic proxy, which implements the bean's interfaces, or a CGLIB proxy, which subclasses the bean's class. Spring Boot defaults to CGLIB.

    The limits follow from this. Only calls that go through the proxy are intercepted, so self-invocation is not. A CGLIB proxy cannot override final classes or final methods, and private methods are never advised. Code that casts a bean to its concrete class may fail with a JDK proxy.

    If you need to advise internal calls, use AspectJ weaving instead, or restructure so the advised method lives on a different bean.

    What the interviewer is checking: Understanding of the mechanism behind many annotations, and its boundaries.

    Likely follow-up: Where in the bean lifecycle are these proxies created?

  26. 26The app fails with a circular dependency or "no qualifying bean". How do you debug it?Advanced

    For "no qualifying bean", I first check whether the class is actually scanned: is it annotated, and is it inside the main class's package tree? Then I check conditions, for example a @ConditionalOnProperty or an active profile that excludes it. Running with --debug prints the conditions evaluation report, and the Actuator beans and conditions endpoints show what was registered. Two candidates for one type is the opposite error, solved with @Primary or @Qualifier.

    Circular dependencies, where A needs B and B needs A, fail at startup with constructor injection, and since Boot 2.6 they are prohibited by default even for setter or field injection. Do not turn the allowing flag on as the fix; break the cycle by extracting the shared logic into a third bean, or by publishing an application event instead of calling directly.

    What the interviewer is checking: A systematic debugging approach and design instinct about cycles.

    Likely follow-up: What is the difference between @Primary and @Qualifier?

  27. 27Your service calls three downstream APIs. How do you make a Spring Boot service resilient to their failures?Advanced

    Start with timeouts on every outbound call, because the default of waiting forever ties up threads. Then add bounded retries with backoff and jitter, only for idempotent operations or with idempotency keys, since retrying a payment can double-charge. Add a circuit breaker so a failing dependency is skipped quickly instead of consuming resources, and a bulkhead or separate pool so one slow API cannot starve the others.

    Libraries such as Resilience4j integrate with Spring Boot through annotations and configuration, and Actuator and Micrometer expose breaker state. Define a fallback that is honest: a cached value, a degraded response, or a clear 503.

    Finally, test the failure modes, not only the happy path. See the microservices course for these patterns in context.

    What the interviewer is checking: Production thinking about failure: timeouts, retries, idempotency and isolation.

    Likely follow-up: How do you decide the retry count and timeout values so retries don't amplify an outage?

Fill the gaps with a free course

If one of these Spring Boot answers felt shaky, these 3 courses cover the same ground step by step: Spring Boot, Microservices Architecture, REST API Development.

More interview questions

Practising Spring Boot for a real opening? Upload your resume to see which open jobs list Spring Boot skills you already have, or browse open roles.