Spring Boot Interview Questions and Answers (2026)
Spring Boot interviews test whether you understand what auto-configuration and the bean lifecycle are actually doing behind the annotations, and where the common pitfalls (self-invocation breaking @Transactional) live. Here are the questions that come up most.
-
How does Spring Boot auto-configuration actually work?
Auto-configuration is driven by
@EnableAutoConfiguration(pulled in transitively by@SpringBootApplication), which triggers Spring to load configuration classes listed inMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(before Boot 2.7 it wasspring.factories) from every jar on the classpath. Each auto-configuration class is heavily annotated with conditional annotations —@ConditionalOnClass(only apply if a certain class is on the classpath, e.g., Tomcat),@ConditionalOnMissingBean(only apply if the developer hasn't already defined their own bean),@ConditionalOnProperty, etc. So Boot essentially inspects what's on your classpath and what beans you've already declared, then wires up sensible defaults — e.g., seeingspring-boot-starter-data-jpaplus an H2 driver auto-configures aDataSourceandEntityManagerFactory. Your own@Beandefinitions always take precedence and effectively "turn off" the matching auto-configuration. -
Explain dependency injection and bean scopes in Spring.
Dependency Injection means Spring's IoC container creates and wires objects (beans) for you rather than you calling
newyourself, which decouples components and makes testing easier via mocking. Spring supports constructor injection (preferred — enables immutability and makes required dependencies explicit), setter injection, and field injection (discouraged — hides dependencies and complicates testing).@Service public class OrderService { private final PaymentClient client; public OrderService(PaymentClient client) { this.client = client; } }Bean scopes control lifecycle:
singleton(default — one instance per Spring container),prototype(new instance every injection/lookup), and web-aware scopesrequest,session,application. Injecting a prototype bean into a singleton needs special handling (e.g.,ObjectProvideror scoped proxies) since the singleton is only wired once. -
What's the difference between @RestController and @Controller?
@Controlleris the base Spring MVC stereotype for a class that handles web requests and typically returns a view name (e.g., a Thymeleaf template) to be resolved and rendered by aViewResolver.@RestControlleris a convenience annotation that combines@Controllerand@ResponseBody— every handler method's return value is written directly to the HTTP response body (usually serialized to JSON via Jackson) instead of being resolved as a view name. So for traditional server-rendered HTML apps you'd use@Controllerwith individual@ResponseBodyon API-only methods if needed, while for a JSON REST API (the common case in microservices),@RestControlleris used on the whole class.@RestController class UserController { @GetMapping("/users/{id}") User get(@PathVariable Long id) { return service.find(id); } } -
What are Spring Boot starters?
Starters are curated dependency descriptors (Maven/Gradle artifacts like
spring-boot-starter-web,spring-boot-starter-data-jpa,spring-boot-starter-security) that bundle a coherent set of libraries for a specific purpose along with compatible versions, so you don't have to manually resolve version conflicts across a dozen libraries. For instance,spring-boot-starter-webpulls in Spring MVC, an embedded Tomcat, Jackson for JSON, and validation libraries. They work hand-in-hand with auto-configuration and Boot's dependency management BOM (spring-boot-dependencies), which pins compatible versions of everything so you typically only specify the starter, not individual version numbers. This is a big reason Boot projects avoid "dependency hell" compared to plain Spring projects where you manually assembled each library. -
How do application.properties/yml and profiles work?
application.properties(or.yml) holds externalized configuration — DB URLs, ports, feature flags — that Spring binds into beans via@Valueor, better, type-safe@ConfigurationPropertiesclasses. Profiles let you have environment-specific overrides:application-dev.yml,application-prod.yml, activated viaspring.profiles.active=dev(as an env var, JVM arg, or in the base file). Boot merges the profile-specific file's properties over the baseapplication.yml, and@Profile("dev")on a@Beanor@Componentconditionally registers it only when that profile is active — handy for swapping a real payment gateway bean for a mock in dev/test. Boot also supports config via environment variables and command-line args, following a well-defined precedence order (command-line args and env vars generally override file-based properties). -
Describe the Spring Bean lifecycle.
Roughly: the container instantiates the bean (constructor), injects dependencies (setters/fields), then calls
Awareinterface callbacks if implemented (e.g.,ApplicationContextAware), then invokes@PostConstruct-annotated methods (orInitializingBean.afterPropertiesSet(), or a custominit-method) for post-injection initialization logic — this is where you'd validate config or warm up a cache. The bean is then ready for use. On container shutdown,@PreDestroymethods (orDisposableBean.destroy()) run for cleanup like closing connections.@Component public class CacheWarmer { @PostConstruct void init() { loadCacheFromDb(); } @PreDestroy void cleanup() { flushCache(); } }BeanPostProcessors can hook in before/after initialization across all beans, which is how features like AOP proxying and
@Autowiredresolution actually get applied. -
What does @Transactional do, and what are common pitfalls?
@Transactionalwraps a method in a database transaction via a dynamically generated proxy — on entry it starts (or joins) a transaction, commits on success, and rolls back on a runtime exception (checked exceptions do NOT trigger rollback by default, onlyRuntimeException/Error, unless you setrollbackFor). The biggest pitfall is "self-invocation": calling an@Transactionalmethod from another method in the same class bypasses the proxy entirely, so the transaction never starts, because Spring AOP proxies only intercept external calls.@Service class OrderService { public void placeOrder() { this.save(); } // NOT transactional — self-call! @Transactional public void save() { ... } }Other pitfalls: marking a method
@Transactionalbut catching the exception inside it (swallowing it prevents rollback), and unintentionally holding a transaction open too long by including slow non-DB work inside it. -
How do you handle exceptions globally in Spring Boot?
@ControllerAdvice(or@RestControllerAdvicefor REST APIs, which also applies@ResponseBody) defines a centralized, cross-cutting exception handler class that applies to all (or selected) controllers, avoiding repetitive try/catch in every endpoint. Inside it,@ExceptionHandlermethods map specific exception types to HTTP responses.@RestControllerAdvice public class ApiExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) { return ResponseEntity.status(404).body(new ErrorResponse(ex.getMessage())); } }This gives consistent error response shapes (useful for API consumers), keeps controllers clean, and can differentiate handling per exception type — e.g., mapping validation errors to 400, auth failures to 401/403, and unexpected exceptions to a generic 500 without leaking stack traces.
-
What are Spring Data JPA repositories and how do they work?
Spring Data JPA lets you define a repository as an interface — extending
JpaRepository<Entity, IdType>— and get CRUD, pagination, and sorting implemented for free without writing implementation code; Spring generates a dynamic proxy implementation at runtime. Beyond the built-in methods, you can declare query methods by naming convention (findByEmailAndActiveTrue), which Spring parses into a JPQL query automatically, or use@Queryfor custom JPQL/native SQL.public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); List<User> findByActiveTrueOrderByCreatedAtDesc(); }Under the hood it's still using JPA/Hibernate as the ORM. A common interview follow-up is the N+1 query problem — lazy-loaded associations fetched in a loop trigger one query per row — solved with
@EntityGraph, JOIN FETCH, or batch fetching. -
What are Actuator endpoints and why are they useful?
spring-boot-starter-actuatorexposes production-ready monitoring/management endpoints over HTTP (and JMX) without you writing them yourself —/actuator/health(app + dependency status, e.g., DB connectivity),/actuator/metrics(JVM memory, HTTP request timings, custom metrics via Micrometer),/actuator/info,/actuator/env(active configuration), and/actuator/loggers(view/change log levels at runtime without redeploying). These integrate naturally with monitoring stacks — Micrometer metrics can be scraped by Prometheus, and/healthis what load balancers and Kubernetes liveness/readiness probes typically poll. By default only/healthand/infoare exposed over HTTP for security reasons; you explicitly opt in to exposing others viamanagement.endpoints.web.exposure.include, and sensitive endpoints should be secured or restricted to an internal management port. -
Embedded Tomcat vs deploying a WAR — what's the tradeoff?
Spring Boot defaults to packaging an executable "fat jar" with an embedded servlet container (Tomcat by default, swappable for Jetty/Undertow), so the app is self-contained and runs with
java -jar app.jar— no separate application server to install/configure, which fits container/cloud-native deployment (Docker, Kubernetes) well and lets each service pin its own server version independently. The alternative is packaging a traditional WAR and deploying it to an external servlet container (e.g., an existing Tomcat/WebLogic instance), which some enterprises require for centralized server management, shared container resources across multiple apps, or compliance reasons. Boot supports this by extendingSpringBootServletInitializerand marking the embedded container dependency asprovidedscope. In practice, most greenfield microservices use the embedded-jar approach since it aligns with immutable, independently deployable containers. -
How do you secure a REST API with Spring Security basics?
Adding
spring-boot-starter-securityauto-configures a default security filter chain requiring authentication on all endpoints. For a real API you typically define aSecurityFilterChainbean specifying which routes are public vs protected, disable CSRF for stateless JSON APIs (CSRF protection is for browser session/cookie-based flows), and configure stateless session management plus a token-based auth mechanism like JWT via a custom filter.@Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .sessionManagement(sm -> sm.sessionCreationPolicy(STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/**").permitAll() .anyRequest().authenticated()) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); }Method-level authorization (
@PreAuthorize("hasRole('ADMIN')")) adds fine-grained control on top of URL-based rules.
Practicing for a real interview? Get live AI help with your answers, in the browser, free to start.
Start a free session