SkillLynk Skill Lynk connect skills with opportunities
Menu

Spring Boot Interview Questions & Answers

Spring Boot interview questions covering dependency injection, REST APIs, configuration, security, and testing -- the framework knowledge most Java backend interviews probe first.

20 Questions ~30 min read Beginner: 2 Intermediate: 13 Advanced: 5

Coding 2

Annotate a class with @RestController, then map HTTP methods to handler methods with @GetMapping/@PostMapping/etc., using @RequestBody/@PathVariable/@RequestParam to bind input.

Detailed Answer

@RestController combines @Controller and @ResponseBody, so returned objects are serialized (typically to JSON via Jackson) directly into the response body instead of being resolved as a view name. A method like `@GetMapping("/users/{id}") public UserDto getUser(@PathVariable Long id)` binds the path variable automatically, and Spring handles content negotiation and serialization.
rest-apispring-boot
Annotate the DTO fields with Bean Validation annotations (@NotNull, @Size, @Email, etc.) and add @Valid to the controller parameter; Spring automatically triggers validation and returns a 400 on failure.

Detailed Answer

Adding `@Valid @RequestBody CreateUserRequest request` to a controller method causes Spring to validate the request body against the constraint annotations on CreateUserRequest before the method body runs. Validation failures throw a MethodArgumentNotValidException, which you typically catch in a global @ControllerAdvice to return a structured 400 response listing which fields failed and why.

Best Practices

Centralize the validation-error-to-response mapping in one @ControllerAdvice handler rather than duplicating error formatting in each controller.
rest-apispring-boot

Conceptual 10

Spring Boot is an opinionated layer on top of Spring that auto-configures common setups and bundles an embedded server, removing most of the manual XML/config Spring traditionally needed.

Detailed Answer

The core Spring Framework provides dependency injection, AOP, and countless modules, but wiring a real application historically required significant XML or Java configuration. Spring Boot adds auto-configuration (sensible defaults based on what's on the classpath), starter dependencies (curated dependency bundles like spring-boot-starter-web), and an embedded servlet container (Tomcat/Jetty by default), so you can run a production-ready app with minimal setup.
spring-bootconfiguration
Spring's IoC container creates and wires beans for you; the three main injection styles are constructor, setter, and field injection.

Detailed Answer

Constructor injection passes dependencies through the constructor and is the recommended default -- it makes dependencies explicit, supports immutability (final fields), and fails fast if a required bean is missing. Setter injection allows optional dependencies to be set after construction. Field injection (@Autowired directly on a field) is the most concise but the least testable, since you can't easily supply a dependency without a container or reflection.

Best Practices

Prefer constructor injection; reserve field injection for quick prototypes, not production code.
dependency-injectionspring-boot
All four are stereotype annotations that register a class as a Spring bean; they mainly differ in semantic intent and, for @Repository, automatic exception translation.

Detailed Answer

@Component is the generic stereotype. @Service marks a business-logic layer bean (semantic only, no extra behavior). @Repository marks a data-access bean and additionally enables Spring's exception translation, converting persistence-specific exceptions into Spring's DataAccessException hierarchy. @Controller marks a Spring MVC web controller whose methods handle HTTP requests (often paired with @ResponseBody, or replaced entirely by @RestController).
spring-bootdependency-injection
@RequestParam reads a query string parameter, @PathVariable reads a segment of the URL path, and @RequestBody deserializes the whole request body into a Java object.

Detailed Answer

@RequestParam is used for values like ?page=2&size=10. @PathVariable binds a templated segment like /users/{id}. @RequestBody is used for POST/PUT payloads where the entire body (usually JSON) maps to a DTO via Jackson. Mixing them up is a common source of 400 errors when the client sends data in a shape the annotation doesn't expect.
rest-api
Singleton (default, one instance per container) and prototype (a new instance per request for the bean) are the core scopes; web-aware scopes like request and session exist for web apps.

Detailed Answer

Singleton is right for stateless services shared across the app. Prototype creates a fresh instance every time the bean is requested from the container -- useful for stateful, non-thread-safe objects. request scope creates one instance per HTTP request and session scope creates one per HTTP session, both useful for holding request/session-specific state without manual ThreadLocal management.

Best Practices

Keep singleton beans stateless (no mutable instance fields representing per-request data) since they're shared across every concurrent request.

Common Mistakes

Storing per-request mutable state in a singleton-scoped bean's instance fields, which causes data to leak or corrupt between concurrent requests.
spring-boot
Aspect-Oriented Programming lets you apply cross-cutting logic (logging, transactions, security) to multiple methods/classes without repeating that code in each one.

Detailed Answer

Spring AOP uses dynamic proxies (JDK proxies for interfaces, CGLIB for classes) to wrap a bean's method calls, letting you define "advice" (code to run before/after/around a method) that applies wherever a pointcut expression matches -- e.g. every method annotated @Transactional, or every method in a *ServiceImpl class. This is how @Transactional and @Cacheable work under the hood without you writing that plumbing manually.

Best Practices

Be aware that self-invocation (a method calling another method on `this`) bypasses the AOP proxy, so annotations like @Transactional silently don't apply in that case.

Common Mistakes

Calling an @Transactional-annotated method from another method in the same class via `this.method()`, which skips the proxy and silently loses the transaction boundary.
aopspring-boot
Both configure the same properties in different formats (flat key-value vs. nested YAML); profile-specific files like application-prod.yml override the base file when that profile is active.

Detailed Answer

YAML supports hierarchical structure more readably than dotted property keys, but both are ultimately flattened into the same PropertySource abstraction internally. Spring Boot loads application.properties/yml first, then layers on application-{profile}.properties/yml for whatever profile is active (set via spring.profiles.active), letting environment-specific values (like a different datasource URL) override the defaults.
configurationspring-boot
@ExceptionHandler methods (often grouped in an @ControllerAdvice class) intercept exceptions thrown from controllers and translate them into a consistent error response.

Detailed Answer

Rather than scattering try/catch blocks across every controller method, a single @ControllerAdvice class can define @ExceptionHandler(SomeException.class) methods that return a structured error body (status code, message, timestamp) whenever that exception type propagates from any controller. This keeps error response formatting consistent across the whole API.

Best Practices

Return a consistent error DTO shape (status, error code, message) from every handler, and map exceptions to the correct HTTP status rather than defaulting everything to 500.

Common Mistakes

Letting unhandled exceptions leak raw stack traces into the HTTP response, which both looks unprofessional and can expose internal implementation details.
rest-apispring-boot
Use plain JUnit/Mockito to instantiate the class directly and mock its dependencies, without loading the Spring context, to keep the test fast.

Detailed Answer

For a pure service class, `@ExtendWith(MockitoExtension.class)` with `@Mock` for dependencies and `@InjectMocks` for the class under test avoids the overhead of starting a Spring application context, so the test runs in milliseconds. Reserve `@SpringBootTest` (which boots the real context) for integration tests that genuinely need wiring, a real or embedded database, or the web layer.

Best Practices

Keep the majority of tests as fast, context-free unit tests; use @SpringBootTest sparingly for true integration coverage.

Common Mistakes

Reaching for @SpringBootTest by default for every test class, which makes the test suite slow to run and slows down the whole team's feedback loop.
testingspring-boot
@Mock (Mockito) creates a plain mock with no Spring context involved; @MockBean replaces a real bean in the Spring application context with a mock, for use inside @SpringBootTest-style integration tests.

Detailed Answer

@Mock is used in pure unit tests where there's no Spring context at all. @MockBean is Spring Boot Test's annotation for swapping out a specific bean inside a loaded application context (e.g. replacing a real external API client with a mock) so the rest of the context wires up normally around it. Using @MockBean forces a context reload if the bean definition differs from a previously cached context, which can slow down a large test suite if overused.

Best Practices

Prefer plain unit tests with @Mock where possible; use @MockBean only when you specifically need the surrounding Spring context.

Common Mistakes

Sprinkling @MockBean across many test classes with slightly different bean sets, causing Spring's test context cache to keep rebuilding and slowing the whole suite down.
testingspring-boot

Architecture 4

Spring Boot scans the classpath and conditionally registers beans based on @ConditionalOnClass/@ConditionalOnMissingBean-style checks defined in auto-configuration classes.

Detailed Answer

Each starter ships auto-configuration classes annotated with conditional annotations (e.g. @ConditionalOnClass(DataSource.class)) that only activate if certain classes are present, certain beans are absent, or certain properties are set. @SpringBootApplication pulls in @EnableAutoConfiguration, which loads these candidate configurations and applies the ones whose conditions match -- letting you override any default simply by defining your own bean of that type.

Best Practices

To override an auto-configured bean, just declare your own @Bean of the same type -- @ConditionalOnMissingBean means yours wins.

Common Mistakes

Fighting auto-configuration with @ComponentScan exclusions or manual bean removal instead of simply defining your own bean, which is the intended override mechanism.
spring-bootconfiguration
Spring instantiates a bean, populates its dependencies, calls any @PostConstruct/InitializingBean hooks, makes it available for use, then calls @PreDestroy/DisposableBean hooks on container shutdown.

Detailed Answer

The container instantiates the bean (via constructor), injects its dependencies, applies BeanPostProcessors (which power features like @Autowired resolution and AOP proxying), invokes any initialization callback (@PostConstruct method, or afterPropertiesSet() if it implements InitializingBean), and the bean is now ready to use. On application shutdown, Spring calls any destruction callback (@PreDestroy, or destroy() if it implements DisposableBean) before releasing the bean.
spring-boot
@Transactional wraps a method in a proxy that begins a transaction before the method runs and commits/rolls back after, based on whether an exception was thrown.

Detailed Answer

By default, @Transactional rolls back only on unchecked exceptions (RuntimeException and Error), not checked exceptions, unless you configure rollbackFor explicitly. Because it's implemented via AOP proxies, calling an @Transactional method from within the same class (self-invocation) bypasses the proxy entirely and the transaction boundary is silently lost -- a very common production bug.

Best Practices

Put @Transactional on the outermost service method that represents the actual business operation, and set rollbackFor(Exception.class) if you need rollback on checked exceptions too.

Common Mistakes

Assuming @Transactional automatically rolls back for any exception, then being surprised a checked exception let a partial write commit.
spring-bootaop
A monolith deploys the whole application as one unit; microservices split it into independently deployable services, each often built as its own small Spring Boot application.

Detailed Answer

Spring Boot's fast startup, embedded server, and minimal configuration make it a natural fit for microservices, where each service is its own deployable JAR. In a microservices setup you typically add service discovery (e.g. Eureka), client-side or gateway-based routing, centralized configuration (Spring Cloud Config), and resilience patterns (circuit breakers) on top of plain Spring Boot to handle the added complexity of many independently-deployed services talking to each other over the network.

Common Mistakes

Adopting microservices before there's an organizational or scaling reason to -- the operational complexity (network calls, distributed tracing, service discovery) is a real cost that a monolith doesn't pay.
microservicesspring-boot

Performance 1

Profile startup with actuator/Spring's built-in startup metrics or a tool like Spring Boot's ApplicationStartup API, then target the actual bottleneck -- often excessive component scanning, slow auto-configuration, or eager bean initialization.

Detailed Answer

Common causes include an overly broad @ComponentScan base package pulling in far more classes than needed, too many auto-configurations being evaluated (visible via --debug or the auto-configuration report), and beans doing expensive work in their constructors or @PostConstruct instead of lazily. Enabling lazy initialization (spring.main.lazy-initialization=true) for non-critical beans, narrowing component scanning, and excluding unused auto-configurations are typical fixes.

Best Practices

Measure first with Spring's own startup instrumentation before guessing at the cause -- 'slow startup' can come from several unrelated sources.
performancespring-boot

Behavioral 1

A strong answer walks through reproducing or narrowing the issue using logs/metrics, forming a hypothesis, verifying it in a safe environment, and shipping a fix with a regression test.

Detailed Answer

Interviewers want to see structured debugging: checking application logs and metrics (or APM traces) first to localize which layer failed, forming a specific hypothesis rather than guessing broadly, reproducing the issue in a lower environment if possible, and confirming the fix addresses the root cause rather than just the symptom -- ideally backed by a test that would have caught the regression.
spring-boot

Security 1

Spring Security is a filter-chain-based framework for authentication and authorization; a request passes through a chain of security filters that authenticate the user and then check access rules before reaching the controller.

Detailed Answer

A typical flow: a login request hits an authentication filter, which delegates to an AuthenticationManager and a UserDetailsService to verify credentials; on success, an Authentication object is stored in the SecurityContext (often backed by a session or, for stateless APIs, a JWT validated on each request). Subsequent requests are checked against configured authorization rules (e.g. hasRole("ADMIN")) before the controller method executes.

Best Practices

For stateless REST APIs, disable session-based security and validate a signed token (e.g. JWT) per request instead of relying on server-side sessions.
spring-securityspring-boot

Scenario-Based 1

Implement it as a servlet filter or Spring interceptor that checks a request counter (often backed by Redis for a distributed deployment) per client key, rejecting requests over the limit with HTTP 429.

Detailed Answer

A common approach is a token-bucket or sliding-window counter keyed by API key or client IP, stored in a fast shared store like Redis so the limit is enforced consistently across multiple application instances (a purely in-memory counter would let each instance apply its own separate limit). The filter checks and decrements the bucket before the request reaches the controller, returning 429 Too Many Requests with a Retry-After header when exhausted.

Best Practices

Put rate limiting state in a shared store (Redis) rather than in-memory once you have more than one application instance, or the limit becomes per-instance instead of global.
scalabilityrest-apispring-boot
No questions match your filters.

Related Skills

Continue Your Career Journey

Explore on SkillLynk

Sign in required

Sign in