Spring Boot Interview Questions and Answers for Experienced Developers

Spring Boot interview questions for experienced and 10+ year Java developers in 2026: auto-configuration, JPA, Security, Actuator, testing, virtual threads, and senior scenario answers.

Published

Updated

Tech reviewed byDeepak Prasad

Spring Boot Interview Questions and Answers for Experienced Developers

Spring Boot interviews for experienced Java developers go far beyond "what is a bean?" Hiring managers want to see that you can ship production APIs—configure auto-wiring correctly, reason about transactions and lazy loading, secure endpoints with OAuth2/JWT, debug slow queries, and explain how your service behaves under load. Loops for 5–10 years of experience often blend framework depth with system design: caching, messaging, deployment on Kubernetes, and trade-offs between monolith modules and microservices.

Below are 45 questions aimed at Spring Boot interview questions for experienced candidates—including senior and 10 years experienced loops. Answers are written so you can learn while prepping: tables, small code samples, with elaborate answers; technical sections include a strong answer sample you can say aloud. Pair this guide with OOP interview questions for SOLID and design-pattern depth, Java interview questions part 1 and part 2 for JVM and concurrency fundamentals, Kafka interview questions for event streaming and messaging depth, Kubernetes interview questions for deploying services to clusters, PostgreSQL interview questions for JPA datasource and query tuning depth, full stack developer interviews for React/Spring integration, Maven interview questions for build and BOM imports, Selenium interview questions for UI test automation alongside @SpringBootTest, and SQL technical interviews when JPA questions turn into query plans.

NOTE
Prep target: Experienced loops favor scenario answers—a REST API with JPA, a failed transaction you debugged, a security filter chain you customized, or a production incident traced with Actuator and logs. Keep one reference project you can whiteboard end to end.

Tested on: Ubuntu 25.04 (Plucky Puffin); kernel 6.14.0-37-generic; OpenJDK 21.0.9.


Interview context and how to prepare

What do Spring Boot interviews test for experienced developers?

Spring Boot is the default way most Java teams bootstrap web applications, batch jobs, and microservices. Interviewers are not checking whether you memorized every starter artifact—they want proof you can build and operate Spring applications.

Typical skill layers:

Layer What interviewers probe
Core & DI Beans, scopes, @Configuration, component scanning
Auto-config How starters wire defaults; when to override
Web layer REST design, validation, exception handling
Data Spring Data JPA, transactions, N+1, migrations
Security Filter chain, JWT/OAuth2, method security
Testing Slice tests, Testcontainers, mocking boundaries
Production Actuator, metrics, profiles, health checks
Modern Java Records as DTOs, virtual threads, Spring Boot 3 / Jakarta
Experience What changes in the room
3–5 years CRUD APIs, basic JPA, starter dependencies
5–8 years Transactions, security, testing strategy, performance
8–10+ years System design, microservices boundaries, operability, mentoring
Spring Boot vs Spring Framework — what is the difference?

Spring Framework is the core inversion-of-control container: beans, AOP, MVC, transaction abstraction, and integration modules. You can build apps with plain Spring, but you assemble a lot manually—XML or Java config, embedded server setup, dependency versions.

Spring Boot sits on top and optimizes for convention over configuration:

Concern Spring Framework alone Spring Boot
Dependency versions You align JAR versions BOM / parent POM (spring-boot-dependencies)
Embedded server You wire Tomcat/Jetty spring-boot-starter-web brings Tomcat by default
Auto-configuration Manual @Configuration Classpath-driven @EnableAutoConfiguration
Run command Deploy WAR to external server java -jar app.jar or spring-boot:run
Production features Add Actuator yourself spring-boot-starter-actuator

Spring Boot does not replace Spring concepts—you still need to understand beans, @Transactional, and MVC. Boot removes boilerplate so you focus on business code.

What is a typical Spring Boot interview loop for 5–10 years experience?

Loops vary by company (product, bank, consultancy, startup), but experienced Java Spring Boot patterns often look like this:

Round Duration Focus
Recruiter / HM 30 min Projects, team size, cloud exposure
Java fundamentals 45–60 min Often ties to Java part 2—collections, concurrency, JVM
Spring Boot deep dive 60–90 min JPA, security, REST, configuration, testing
System design 45–60 min Microservice boundaries, messaging, caching, deployment
Live coding / review 45–60 min Fix a controller, write a repository query, debug a test
Behavioral 30–45 min Incidents, deadlines, code review culture

For 10 years experienced roles, expect more architecture and operability—how you roll out config changes, handle schema migrations, and observe services in Kubernetes or VM fleets.

What is a realistic 4–6 week prep plan?

Treat prep as one reference application you can explain aloud—not fifty disconnected flashcards.

Week Focus Concrete output
1 Core Boot — starters, auto-config, profiles Run a small REST app; list beans with Actuator
2 Data — JPA, transactions, Flyway CRUD + custom query; reproduce and fix N+1
3 Security — JWT or OAuth2 resource server Protect one endpoint; document filter chain
4 Testing — slices + Testcontainers @WebMvcTest, @DataJpaTest, one integration test
5 Production — metrics, logging, virtual threads Enable Actuator; try spring.threads.virtual.enabled on Java 21
6 Scenarios — design + stories Whiteboard order service; rehearse two production incidents

Review Maven BOM imports if interviewers ask how Spring Boot aligns dependency versions.


Core Spring Boot and dependency injection

What does @SpringBootApplication do?

@SpringBootApplication is a composed annotation that combines three important switches:

java
@SpringBootApplication
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

Under the hood it typically includes:

Annotation Role
@SpringBootConfiguration Marks the class as a source of @Bean definitions (specialized @Configuration)
@EnableAutoConfiguration Imports auto-configuration classes based on classpath
@ComponentScan Scans the package of the application class and sub-packages for stereotypes

SpringApplication.run bootstraps the context, starts the embedded web server (if spring-boot-starter-web is present), and registers shutdown hooks.

Common follow-up: How do you exclude an auto-configuration? Use @SpringBootApplication(exclude = SomeAutoConfiguration.class) or spring.autoconfigure.exclude in properties.

A strong answer is:

@SpringBootApplication enables component scanning and auto-configuration from my main class package downward, and SpringApplication.run starts the embedded container and refreshes the application context.

How does Spring Boot auto-configuration work?

Auto-configuration is conditional bean registration. Spring Boot loads candidate configuration classes listed in:

  • META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (Boot 3.x)
  • Older Boot 2.x used spring.factories

Each auto-config class uses @ConditionalOn* annotations, for example:

Condition Meaning
@ConditionalOnClass Classpath contains a type (e.g. DataSource)
@ConditionalOnMissingBean User has not defined their own bean of that type
@ConditionalOnProperty Property flag is set
@ConditionalOnWebApplication Running as servlet or reactive web app

Example flow for JPA:

  1. Classpath has spring-boot-starter-data-jpa and a JDBC driver.
  2. DataSourceAutoConfiguration creates a DataSource if you did not define one.
  3. HibernateJpaAutoConfiguration sets up EntityManagerFactory when JPA is on the classpath.

You override by defining your own @Bean or setting properties (spring.datasource.url, etc.). In interviews, mention you can inspect what applied via the conditions report (/actuator/conditions when exposed).

A strong answer is:

Auto-configuration registers beans only when classpath and properties match, and backs off when I define my own bean—so defaults are safe to start with but fully overridable.

What are Spring Boot starters and why use them?

Starters are dependency bundles that pull in libraries plus matching auto-configuration. They keep your pom.xml or build.gradle readable.

Starter Brings in (high level)
spring-boot-starter-web Spring MVC, Jackson, embedded Tomcat
spring-boot-starter-data-jpa Hibernate, Spring Data JPA, JDBC
spring-boot-starter-security Spring Security filter chain
spring-boot-starter-test JUnit, Mockito, AssertJ, Spring Test
spring-boot-starter-actuator Production endpoints and metrics
spring-boot-starter-validation Bean Validation (Hibernate Validator)

Starters are not magic—they are curated Maven coordinates. Custom starters follow the same pattern for internal platforms.

Interview tip: connect starters to the Spring Boot BOM imported by spring-boot-starter-parent or spring-boot-dependencies so versions stay aligned—see Maven interview questions.

A strong answer is:

Starters group dependencies that work together and trigger the right auto-configuration, so I add one coordinate instead of juggling ten JAR versions manually.

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

All are stereotypes of @Component—they mark classes for component scanning and register them as Spring beans.

Stereotype Typical use Special behavior
@Component Generic bean None
@Service Business logic layer Semantic only (documentation)
@Repository Data access Translates persistence exceptions to Spring DataAccessException
@Controller MVC controller returning views Pair with @ResponseBody or use @RestController
@RestController REST API @Controller + @ResponseBody on class

Layering interviewers expect:

text
@RestController → @Service → @Repository / JpaRepository

Keep controllers thin—validation and HTTP mapping only; business rules in services.

A strong answer is:

Stereotypes are all discoverable beans; the names document layer intent, and @Repository adds persistence exception translation while @RestController is the REST entry point.

How does dependency injection work in Spring Boot?

Spring creates objects (beans) and wires dependencies through the container.

Common injection styles:

Style Example Notes
Constructor public OrderService(OrderRepo repo) Preferred—immutable, test-friendly
Field @Autowired private OrderRepo repo Works but harder to test; avoid in new code
Setter @Autowired setRepo(...) Optional dependencies

@Autowired resolves by type; use @Qualifier when multiple beans share a type.

Scopes matter in experienced loops:

Scope Behavior
singleton (default) One instance per container
prototype New instance per injection
request / session Web scopes for per-request state

Circular dependencies: constructor injection between two singletons fails at startup—fix by redesigning boundaries or using @Lazy sparingly.

A strong answer is:

I use constructor injection so dependencies are explicit and required at startup; Spring resolves beans from the context by type and honors scope and qualifier metadata.

When do you use @Configuration and @Bean instead of @Component?

Use @Configuration classes when you need programmatic bean setup—third-party classes you cannot annotate, conditional beans, or complex factory logic.

java
@Configuration
public class JacksonConfig {

    @Bean
    @ConditionalOnProperty(name = "app.json.pretty", havingValue = "true")
    ObjectMapper objectMapper() {
        return JsonMapper.builder()
            .enable(SerializationFeature.INDENT_OUTPUT)
            .build();
    }
}
Approach When
@Component on your class You own the type; let Spring construct it
@Bean method in @Configuration You configure a library class or need explicit lifecycle
Auto-configuration Framework provides sensible default

@Configuration classes are proxied so @Bean methods stay singleton-safe when they call each other.

A strong answer is:

I put my own business types on @Service/@Repository, and use @Configuration + @Bean when I integrate libraries or need conditional factory methods the framework cannot guess.


Configuration, profiles, and Spring Boot 3

application.properties vs application.yml — how do you choose?

Both feed the same Environment abstraction. Spring Boot loads, in order of precedence (higher wins):

  1. Command-line args
  2. SPRING_APPLICATION_JSON
  3. Servlet config / JNDI (legacy)
  4. OS environment variables
  5. application-{profile}.properties|yml
  6. application.properties|yml
Format Pros
.properties Simple, flat, universal
.yml Hierarchy without repeating prefixes; readable for nested config

Example profile file: application-prod.yml activated with spring.profiles.active=prod.

Relaxed binding maps spring.datasource.urlSPRING_DATASOURCE_URL in environment variables—important for Kubernetes and cloud deployment interviews.

A strong answer is:

I pick YAML when configuration is nested and repeated prefixes would clutter properties; either way I keep secrets out of git and override with environment-specific files or env vars in production.

What are Spring profiles and how do you use them?

Profiles label beans and configuration for environments—dev, test, staging, prod.

Ways to activate:

properties
spring.profiles.active=dev,local

Or @Profile("dev") on a @Configuration or @Bean:

java
@Configuration
@Profile("dev")
public class DevDataSourceConfig { /* in-memory H2 */ }
Use case Profile pattern
Local H2 vs prod PostgreSQL @Profile("dev") / @Profile("prod")
Mock payment gateway @Profile("!prod")
Integration tests @ActiveProfiles("test") on test class

Avoid profile explosion—prefer externalized config (URLs, feature flags) over duplicating entire @Configuration classes per environment.

A strong answer is:

Profiles switch which beans and property files load per environment; I use them for environment-specific infrastructure while keeping business code identical across profiles.

How do you externalize secrets in a Spring Boot production deployment?

Never commit secrets to git. Common patterns:

Pattern How it works
Environment variables SPRING_DATASOURCE_PASSWORD injected by K8s/VM
Secret managers AWS Secrets Manager, Azure Key Vault, HashiCorp Vault
Spring Cloud Config Central server with encrypted values
Kubernetes secrets Mounted as files; bind with spring.config.import

Spring Boot 2.4+ supports:

properties
spring.config.import=optional:vault://

Operational practices interviewers like:

  • Rotate credentials without redeploying code
  • Least-privilege DB users per service
  • No secrets in Actuator env dump exposed publicly

A strong answer is:

Secrets live in the platform secret store or environment injection, referenced by property placeholders at runtime—never hard-coded and never logged by my application.

@ConfigurationProperties vs @Value — when do you use each?
Feature @Value("${app.page-size}") @ConfigurationProperties(prefix="app")
Binding Single property Groups related properties on a type-safe class
Validation Manual Works with @Validated + JSR-303
Relaxed binding Limited pageSizepage-size
IDE support Weaker Metadata in spring-configuration-metadata.json
java
@ConfigurationProperties(prefix = "app.pagination")
public record PaginationProps(int pageSize, int maxPageSize) {}

Enable with @EnableConfigurationProperties(PaginationProps.class) or @ConfigurationPropertiesScan.

Use @Value for one-off toggles; use @ConfigurationProperties for structured config you pass around as a bean.

A strong answer is:

I use @ConfigurationProperties for grouped, validated settings with clear prefixes, and reserve @Value for simple single-property injection.

What changed in Spring Boot 3 and the Jakarta EE namespace?

Spring Boot 3 requires Java 17+ and migrates javax.* enterprise APIs to jakarta.* (Servlet, JPA, Validation, etc.).

Area Impact
Java baseline 17 minimum; teams adopt 21 for virtual threads
Jakarta packages jakarta.persistence.Entity, jakarta.validation.Valid
Security OAuth2 resource server improvements; lambda DSL defaults
Observability Micrometer Observation API, native tracing hooks
AOT / native GraalVM native image support via Spring AOT

Migration interview talking points:

  • Update imports in entities and controllers
  • Confirm third-party libs support Jakarta
  • Re-run integration tests and security config

Pair with Java part 2 for records and virtual threads on modern JDKs.

A strong answer is:

Boot 3 moves the ecosystem to Jakarta namespaces and Java 17+, and adds first-class observability and native compilation paths—I plan migrations by dependency compatibility and regression tests, not search-and-replace alone.


Spring Data JPA, transactions, and persistence

How does Spring Data JPA simplify data access?

Spring Data JPA generates repository implementations from interfaces—you declare queries by method name, @Query, or specifications.

java
public interface OrderRepository extends JpaRepository<Order, Long> {

    List<Order> findByStatusOrderByCreatedAtDesc(OrderStatus status);

    @Query("select o from Order o join fetch o.customer where o.id = :id")
    Optional<Order> findWithCustomer(@Param("id") Long id);
}
Concept Role
JpaRepository CRUD + paging + batch helpers
Derived queries findBy...And... parsed at startup
@Query JPQL or native SQL when derived names are awkward
Projections Interface or DTO views without loading full entities

Under the hood: Spring Data creates a JDK proxy that delegates to EntityManager. You still need to understand JPA mapping, flush timing, and SQL—see SQL interviews for index and join depth.

A strong answer is:

Spring Data JPA removes boilerplate DAO code; I use repositories for query declaration but still own entity design, fetch strategy, and transaction boundaries in the service layer.

What is the N+1 problem in JPA and how do you fix it?

N+1 happens when you load N parent rows, then trigger one extra query per row for a lazy association—classic with OneToMany or ManyToOne defaults.

Symptoms:

  • API looks fine in dev with little data
  • Production list endpoint fires hundreds of SQL statements
  • DB CPU spikes; latency grows with page size

Fixes:

Fix When
join fetch in JPQL Controlled fetch in one query
@EntityGraph Declarative fetch plan on repository method
DTO projection Select only columns you need
Batch fetching hibernate.default_batch_fetch_size
Redesign API Avoid returning deep object graphs
java
@Query("select o from Order o join fetch o.items where o.status = :status")
List<Order> findWithItems(@Param("status") OrderStatus status);

Detect with spring.jpa.show-sql=true in dev, Hibernate statistics, or APM traces.

A strong answer is:

N+1 is lazy loading multiplied by row count; I fix it with explicit fetch joins or projections and verify with SQL logging or metrics—not by blindly switching everything to EAGER.

Explain @Transactional propagation and rollback rules.

@Transactional defines a unit of work bound to a persistence context (for JPA) and database connection.

Common propagation values:

Propagation Behavior
REQUIRED (default) Join caller's transaction or start new
REQUIRES_NEW Suspend caller; always new transaction
NESTED Nested savepoint if supported
SUPPORTS Run non-transactionally if none exists
NOT_SUPPORTED Suspend existing transaction
MANDATORY Must run inside existing transaction
NEVER Must not run inside a transaction

Rollback rules:

  • Unchecked exceptions roll back by default
  • Checked exceptions commit unless you set rollbackFor
  • Self-invocation (this.save()) bypasses the proxy—call through another bean or refactor
java
@Transactional(rollbackFor = Exception.class)
public void placeOrder(PlaceOrderCommand cmd) { /* ... */ }

A strong answer is:

I put @Transactional on the service layer with explicit rollback rules, understand propagation when calling external systems, and avoid self-invocation traps that skip the transactional proxy.

Lazy vs eager loading — when do you use each?
Fetch type Behavior Risk
LAZY (default on collections) Loads association when accessed N+1 if accessed in a loop
EAGER Loads with parent Over-fetching, cartesian products

Default rule: prefer LAZY; fetch intentionally in queries for each use case.

EAGER on OneToMany is a common production incident—large joins and memory pressure.

For read-heavy screens, prefer read models: DTO queries, materialized views, or CQRS-style separation instead of tuning fetch types globally.

A strong answer is:

I keep associations lazy by default and fetch exactly what each endpoint needs with join fetch or projections—never global EAGER to paper over design gaps.

Why separate entity and DTO in Spring Boot APIs?

Entities map to database tables and carry JPA annotations, lazy associations, and lifecycle concerns. DTOs shape what crosses the API boundary.

Reasons to separate:

Concern Entity exposure risk
Serialization Jackson may trigger lazy loads or expose internals
Security Password hash or internal flags leak in JSON
API stability Schema changes should not equal table redesign
Performance DTOs carry only needed fields

Java records make immutable DTOs concise:

java
public class RecordDtoDemo {
    public record OrderResponse(Long id, String status, java.time.Instant createdAt) {}

    public static void main(String[] args) {
        var order = new OrderResponse(42L, "PAID", java.time.Instant.parse("2026-06-27T10:00:00Z"));
        System.out.println(order.id() + " " + order.status());
    }
}
Output

When you click Run, you should see 42 PAID on one line—the record exposes accessors without boilerplate getters.

Map with MapStruct, manual mappers, or Spring's mapping helpers—avoid exposing JpaRepository entities directly from controllers.

A strong answer is:

Entities model persistence; DTOs model contracts—I map between them so API evolution, security, and fetch strategy stay under my control.

How do you manage database schema migrations in Spring Boot?

Flyway and Liquibase version schema changes alongside application code.

Flyway example on classpath:

text
src/main/resources/db/migration/V1__create_orders.sql
src/main/resources/db/migration/V2__add_order_index.sql
properties
spring.flyway.enabled=true
spring.jpa.hibernate.ddl-auto=validate
Setting Production intent
ddl-auto=validate Hibernate checks mapping matches DB; does not mutate schema
ddl-auto=update Dev only—unsafe for prod
Flyway/Liquibase Repeatable, reviewed SQL or XML changelogs

Interview scenario: blue/green deploy with backward-compatible migrations (expand-contract pattern)—add column nullable first, deploy code, backfill, add constraint later.

A strong answer is:

I treat schema as code—Flyway migrations in the repo, ddl-auto=validate in production, and backward-compatible steps so rolling deploys never break old instances.

How do you implement pagination with Spring Data?

Use Pageable and return Page<T> or Slice<T>:

java
@GetMapping("/orders")
public Page<OrderResponse> list(@RequestParam(defaultValue = "0") int page,
                                @RequestParam(defaultValue = "20") int size,
                                Pageable pageable) {
    return orderService.findOrders(pageable);
}
Return type Use when
Page<T> You need total count (extra COUNT query)
Slice<T> Infinite scroll; next-page check only
ScrollPosition (newer APIs) Keyset / seek pagination for large tables

Sort: ?sort=createdAt,desc. Cap size in validation to prevent abuse.

For very large tables, prefer keyset pagination over deep OFFSET—see SQL interviews.

A strong answer is:

I expose page and size with sensible caps, use Page when totals matter and Slice or keyset when OFFSET becomes expensive at scale.


Spring Security

How does the Spring Security filter chain work?

Spring Security is a chain of servlet filters that run before your dispatcher servlet.

Simplified order:

  1. Security context persistence
  2. Logout / anonymous / session management
  3. Authentication filters (form login, Basic, Bearer token, etc.)
  4. Authorization (access rules, method security)
  5. Exception translation to 401/403

In Spring Boot 3, configure with a SecurityFilterChain bean:

java
@Bean
SecurityFilterChain apiSecurity(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable())
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/actuator/health").permitAll()
            .anyRequest().authenticated())
        .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
    return http.build();
}

Stateless REST APIs typically disable CSRF and use token auth; session-based apps keep CSRF protection.

A strong answer is:

Requests pass through ordered security filters that authenticate credentials and enforce authorization before they reach my controller—I configure one SecurityFilterChain bean per security domain.

Walk through JWT authentication in a Spring Boot REST API.

Typical stateless JWT flow:

Step Actor Action
1 Client POST credentials to /login or external IdP
2 Auth server Validates user; issues signed JWT (access + optional refresh)
3 Client Sends Authorization: Bearer <token> on API calls
4 Resource server Validates signature, expiry, audience, issuer
5 Spring Security Builds Authentication with granted authorities
6 Controller @PreAuthorize or URL rules enforce fine-grained access

Spring Boot setup:

  • spring-boot-starter-oauth2-resource-server
  • spring.security.oauth2.resourceserver.jwt.issuer-uri pointing to IdP metadata

Validate: clock skew, key rotation (JWKS endpoint), never log full tokens.

A strong answer is:

The client presents a Bearer JWT; Spring's resource server validates issuer and signature, maps claims to authorities, and my authorization rules run before business logic executes.

OAuth2 resource server vs OAuth2 client — what is the difference?
Role Your app is… Typical use
Resource server API protecting resources Validates incoming JWTs or opaque tokens
OAuth2 client App calling other APIs on behalf of a user Authorization code flow, token exchange
Authorization server Issues tokens Keycloak, Entra ID, Okta, or Spring Authorization Server

A Spring Boot API is usually a resource server. A backend-for-frontend might be both client (to downstream APIs) and resource server (to the browser).

Confuse these in interviews and you will mix up redirect URIs with JWT issuer configuration.

A strong answer is:

My REST API is a resource server that validates tokens; if it must call Google or a partner API with user consent, I add OAuth2 client support for the outbound leg.

Do you need CSRF protection for REST APIs?

CSRF protects cookie-based sessions from cross-site form posts. For stateless JWT in Authorization header, CSRF risk is lower because browsers do not attach custom headers cross-origin without CORS.

App style CSRF
Session cookie auth Enable CSRF (or use SameSite cookies + double-submit)
Bearer token in header Often disabled for pure APIs
Browser cookie + SPA Careful—use SameSite, CSRF tokens, or BFF pattern

If you store JWT in HttpOnly cookies from a SPA, CSRF matters again—see full stack interviews for cookie vs header trade-offs.

A strong answer is:

I enable CSRF when authentication relies on session cookies; for header-based JWT APIs I disable CSRF but still enforce CORS and never move tokens into cookies without a CSRF strategy.

How does method-level security with @PreAuthorize work?

Enable with @EnableMethodSecurity. Annotate service or controller methods:

java
@PreAuthorize("hasRole('ADMIN') or #order.customerId == authentication.principal.id")
public OrderDto getOrder(Long orderId, Order order) { /* ... */ }

Spring evaluates SpEL expressions after authentication. authentication.principal is your UserDetails or JWT claims adapter.

Annotation Use
@PreAuthorize Check before method runs
@PostAuthorize Check return value
@Secured("ROLE_ADMIN") Simple role list

Prefer service-layer enforcement so all entry points (REST, messaging, scheduler) share rules.

A strong answer is:

Method security applies SpEL checks on top of URL rules—I centralize authorization on services with @PreAuthorize so every caller path respects the same policy.


REST APIs, validation, and error handling

What are REST API best practices in Spring Boot?
Practice Detail
Resource URLs Nouns (/orders/{id}), not verbs
HTTP verbs GET read, POST create, PUT replace, PATCH partial, DELETE remove
Status codes 201 + Location on create; 404 when missing; 409 on conflict
Idempotency PUT/DELETE idempotent; POST is not—use keys for payments
Versioning URL (/v1/), header, or media type—pick one and document
Pagination Query params or Pageable; link headers optional

Keep controllers thin:

java
@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
public class OrderController {
    private final OrderService orderService;

    @PostMapping
    ResponseEntity<OrderResponse> create(@Valid @RequestBody CreateOrderRequest req) {
        OrderResponse created = orderService.create(req);
        URI location = URI.create("/api/v1/orders/" + created.id());
        return ResponseEntity.created(location).body(created);
    }
}

Document with springdoc-openapi or Spring REST Docs for consumer contracts.

A strong answer is:

I model resources with clear HTTP semantics, return correct status codes and DTOs, version intentionally, and document the API so frontend and mobile teams integrate without guesswork.

How do you validate request bodies with Bean Validation?

Add spring-boot-starter-validation and annotate DTOs:

java
public record CreateOrderRequest(
    @NotNull Long customerId,
    @NotEmpty @Size(max = 50) List<@NotNull @Positive Integer> itemIds
) {}

Controller:

java
@PostMapping
public OrderResponse create(@Valid @RequestBody CreateOrderRequest req) { /* ... */ }

Validation runs before your method body; failures throw MethodArgumentNotValidException—handle globally (next question).

Custom constraints: @interface + ConstraintValidator for domain rules (e.g. valid SKU format).

A strong answer is:

I validate at the boundary with JSR-303 annotations on DTOs, add custom validators for domain rules, and return consistent 400 responses with field-level errors.

How do you handle exceptions globally with @ControllerAdvice?

@ControllerAdvice centralizes exception mapping to HTTP responses:

java
@RestControllerAdvice
public class ApiExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    ResponseEntity<ProblemDetail> handleValidation(MethodArgumentNotValidException ex) {
        ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);
        problem.setTitle("Validation failed");
        // map field errors to problem properties
        return ResponseEntity.badRequest().body(problem);
    }

    @ExceptionHandler(OrderNotFoundException.class)
    ResponseEntity<ProblemDetail> handleNotFound(OrderNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, ex.getMessage()));
    }
}

Prefer RFC 7807 Problem Details (ProblemDetail in Spring 6) over ad-hoc JSON error shapes.

Never leak stack traces to clients in production; log server-side with correlation IDs.

A strong answer is:

@ControllerAdvice maps domain and validation exceptions to stable Problem Details responses while full diagnostics go to structured logs.

How do you choose HTTP status codes in Spring Boot APIs?
Situation Status
Success GET 200 OK
Created resource 201 Created + Location
Accepted async job 202 Accepted
No content success 204 No Content
Validation error 400 Bad Request
Missing auth 401 Unauthorized
Authenticated but forbidden 403 Forbidden
Missing resource 404 Not Found
Business rule conflict 409 Conflict
Precondition failed (ETag) 412 Precondition Failed
Rate limited 429 Too Many Requests
Server error 500 — only for unexpected failures

Use domain exceptions mapped in @ControllerAdvice so controllers stay clean.

A strong answer is:

I map business outcomes to intentional status codes—404 for missing entities, 409 for conflicts, 400 for bad input—and reserve 500 for truly unexpected exceptions we alert on.

PUT vs PATCH — how do you implement partial updates?
Verb Semantics Implementation
PUT Replace entire resource Client sends full representation
PATCH Partial update JSON Merge Patch or JSON Patch

Spring example for partial update:

java
@PatchMapping("/{id}")
public OrderResponse patch(@PathVariable Long id,
                           @RequestBody Map<String, Object> updates) {
    return orderService.applyPatch(id, updates);
}

Production services often use explicit patch DTOs instead of open maps—type safety and validation.

Concurrency: use ETags or version columns (@Version) to prevent lost updates—return 409 on conflict.

A strong answer is:

PUT replaces the whole resource; PATCH applies a controlled partial update with validation and optimistic locking when multiple clients edit the same row.


Testing, Actuator, and observability

@SpringBootTest vs slice tests — when do you use each?
Annotation Loads Use for
@SpringBootTest Full context (slow) End-to-end integration
@WebMvcTest MVC layer only Controller mapping, security, JSON
@DataJpaTest JPA + in-memory or Testcontainers DB Repositories, queries
@JsonTest Jackson Serialization contracts
@RestClientTest REST clients Outbound HTTP client behavior

Rule: test narrow by default, widen when integration risk appears.

@SpringBootTest(webEnvironment = RANDOM_PORT) + TestRestTemplate or WebTestClient for full HTTP stack.

A strong answer is:

I use slice tests for fast feedback on controllers and repositories, and a small set of @SpringBootTest or Testcontainers tests to prove the wiring that slices mock away.

How do @WebMvcTest and @DataJpaTest work?

@WebMvcTest (example):

java
@WebMvcTest(OrderController.class)
@Import(OrderService.class) // or @MockBean OrderService
class OrderControllerTest {

    @Autowired MockMvc mockMvc;
    @MockBean OrderRepository orderRepository;

    @Test
    void returns404WhenMissing() throws Exception {
        when(orderRepository.findById(1L)).thenReturn(Optional.empty());
        mockMvc.perform(get("/api/v1/orders/1"))
            .andExpect(status().isNotFound());
    }
}

Only MVC infrastructure starts—no full database.

@DataJpaTest:

java
@DataJpaTest
class OrderRepositoryTest {
    @Autowired OrderRepository orders;
    @Autowired TestEntityManager em;

    @Test
    void findsByStatus() { /* persist + query */ }
}

Uses @Transactional rollback by default; add Testcontainers for dialect-specific SQL.

A strong answer is:

@WebMvcTest exercises HTTP contracts with mocked collaborators; @DataJpaTest proves queries against a real persistence context without booting the entire application.

How do Testcontainers improve Spring Boot integration tests?

Testcontainers spins real PostgreSQL, Kafka, Redis, etc. in Docker during tests.

java
@SpringBootTest
@Testcontainers
class OrderApiIT {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");

    @DynamicPropertySource
    static void registerProps(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }
}

Benefits:

  • Catch SQL dialect and constraint issues H2 hides
  • Test Flyway migrations realistically
  • Reproducible CI with Docker available

Trade-off: slower than in-memory DB—keep the suite small and tagged.

A strong answer is:

Testcontainers gives me production-like dependencies in CI—I use it for migration and integration paths that H2 cannot represent faithfully.

What is Spring Boot Actuator and which endpoints matter in production?

Actuator exposes operational endpoints over HTTP or JMX:

Endpoint Purpose
/actuator/health Liveness/readiness (K8s probes)
/actuator/info Build/git metadata
/actuator/metrics Micrometer metrics
/actuator/prometheus Prometheus scrape format
/actuator/loggers Tune log levels at runtime

Secure aggressively:

properties
management.endpoints.web.exposure.include=health,info,prometheus
management.endpoint.health.show-details=when_authorized

Custom health indicators implement HealthIndicator for downstream dependencies (DB, queue).

A strong answer is:

Actuator is how operators check health and scrape metrics—I expose the minimum endpoints, protect them with auth/network policy, and add custom health checks for critical dependencies.

How do logging and distributed tracing work in Spring Boot 3?

Spring Boot 3 uses Micrometer Observation to correlate logs, metrics, and traces.

Practices:

Practice Detail
Structured logging JSON logs with traceId, spanId (Logback encoder)
Correlation IDs Propagate X-Correlation-ID in filters
Tracing bridge OpenTelemetry or Brave with Zipkin/Jaeger/OTLP export
MDC Map diagnostic context in OncePerRequestFilter
properties
management.tracing.sampling.probability=1.0

In incidents, you pivot from user report → trace ID → slow SQL span—interviewers want that workflow, not just "we use logs."

A strong answer is:

I emit structured logs and traces with shared correlation IDs so I can follow one request from gateway through controller, service, and database query during an outage.


Microservices, resilience, and messaging

Monolith vs microservices — when does Spring Boot fit each?

Spring Boot supports modular monoliths and microservices equally well—the question is operational cost.

Approach Spring Boot pattern
Modular monolith Single deployable; modules as packages or Gradle/Maven multi-modules
Microservices One service per bounded context; independent DB
Strangler fig Extract hot paths gradually behind API gateway

Extract a service when you need independent scaling, deployment, or team ownership—not because the monolith hit arbitrary line count.

Spring tools for microservices:

  • Spring Cloud OpenFeign — declarative HTTP clients
  • Spring Cloud Gateway — edge routing
  • Spring Cloud Config — central configuration

See full stack monolith vs micro for product-level framing.

A strong answer is:

I start with a well-bounded Spring Boot monolith and split services only when scaling or ownership forces the operational investment—not by default.

Explain Spring Cloud Config, Gateway, and service discovery at interview level.
Component Role
Config Server Git-backed central application.yml; clients refresh with /actuator/refresh or Spring Cloud Bus
Gateway Reactive edge: routing, rate limiting, auth termination
Discovery (Eureka, Consul) Service registry so clients find instances dynamically
Load balancing Spring Cloud LoadBalancer with RestTemplate/WebClient

Modern deployments often replace Eureka with Kubernetes DNS and Config Server with GitOps + sealed secrets—still know the Spring Cloud abstractions for legacy enterprise stacks.

A strong answer is:

Spring Cloud centralizes config and routing; in Kubernetes I may use native ingress and ConfigMaps instead, but the problems—dynamic endpoints and environment-specific settings—stay the same.

How do circuit breakers work with Resilience4j in Spring Boot?

Resilience4j implements fault tolerance patterns:

Pattern Purpose
Circuit breaker Stop calling failing dependency; fail fast
Retry Transient errors with backoff
Rate limiter Protect your service
Bulkhead Isolate thread pools
java
@CircuitBreaker(name = "inventory", fallbackMethod = "fallbackStock")
public StockResponse checkStock(Long skuId) {
    return inventoryClient.getStock(skuId);
}

States: CLOSED → OPEN (after failure threshold) → HALF_OPEN (probe).

Expose metrics via Micrometer; tune thresholds from production data, not guesses.

A strong answer is:

I wrap outbound calls with circuit breakers and fallbacks so cascading failures do not take down my API, and I monitor breaker state to know when dependencies recover.


Modern Java, performance, and caching

How do virtual threads work in Spring Boot on Java 21?

Virtual threads (Project Loom) are lightweight threads scheduled on carrier platform threads—ideal for blocking I/O heavy workloads.

Enable in Spring Boot 3.2+:

properties
spring.threads.virtual.enabled=true

Tomcat and @Async can use virtual threads for request handling when configured.

Workload Fit
Many concurrent blocking JDBC/HTTP calls Good candidate
CPU-bound computation Stick to platform threads / pool sizing

Caveats interviewers mention:

  • Pinning on synchronized blocks (improving over JDK releases)
  • Thread-local assumptions in libraries
  • Measure—not every app needs virtual threads on day one

Connect to Java part 2 virtual threads for JVM-level detail.

A strong answer is:

On Java 21 I enable Spring Boot virtual thread support for I/O-heavy APIs, load-test against platform-thread baselines, and watch for pinning or thread-local issues in dependencies.

What are GraalVM native images with Spring Boot?

Spring Native / AOT compiles apps ahead-of-time for faster startup and lower memory—useful for serverless and dense Kubernetes.

Trade-offs:

Benefit Cost
Fast cold start Longer build times
Lower RSS Reflection hints; limited dynamic behavior
Smaller containers Some libraries need reachability metadata

Process:

  • Spring AOT generates reflection/proxy config at build time
  • native-maven-plugin or Gradle native build produces executable

Not every Spring app is a native candidate—validate with benchmarks before committing.

A strong answer is:

Native images trade build complexity for startup and memory wins—I use them when cold start or footprint dominates cost, after proving our Spring features and libraries are native-compatible.

How does Spring caching with @Cacheable work?

Enable with @EnableCaching. Annotate read methods:

java
@Cacheable(value = "orders", key = "#id")
public OrderDto findById(Long id) {
    return orderRepository.findById(id).map(mapper::toDto).orElseThrow();
}

@CacheEvict(value = "orders", key = "#id")
public void delete(Long id) { orderRepository.deleteById(id); }

Providers: Caffeine (local), Redis (distributed).

Concern Practice
Stale data TTL + eviction on writes
Stampede Sync cache load or probabilistic early expiration
Serialization DTOs in Redis, not lazy entities

A strong answer is:

I cache expensive reads with explicit keys and TTL, evict on mutations, and choose Redis when multiple instances need a shared cache.


Senior scenarios and final prep

Scenario: A Spring Boot API is slow in production — how do you debug?

Structured approach interviewers want:

Step Action
1 Confirm scope—one endpoint or global? spike vs gradual?
2 Check metrics (latency percentiles, error rate, thread pool, DB pool)
3 Pull traces for slow requests—identify DB, external HTTP, or GC
4 Inspect SQL—N+1, missing index, lock waits (SQL prep)
5 Review recent deploys—config, pool size, feature flag
6 Reproduce in staging with production-like data volume
7 Fix, load-test, roll out with canary

Tools: Actuator metrics, APM (Datadog, New Relic), Hibernate SQL log (dev only), pg_stat_statements, heap dump if GC thrash.

A strong answer is:

I start with metrics and traces to see whether latency is database, downstream HTTP, or pool exhaustion, reproduce with realistic data, fix the root cause—often N+1 or missing index—and verify with load tests before full rollout.

What should you rehearse the week before a senior Spring Boot interview?

Checklist:

  • Whiteboard one service: controller → service → repo → DB + auth filter
  • Explain a transaction bug you fixed (rollback, propagation, self-invocation)
  • Explain a security choice (JWT resource server, roles, method security)
  • Walk through testing pyramid for that service
  • Two STAR stories—production incident and performance win
  • Trade-off answers: monolith vs micro, cache invalidation, optimistic locking
  • Java fundamentals refresh—part 1 and part 2
  • Build/deploy story—Maven/Gradle, Docker, CI, health probes

A strong answer is:

I rehearse one real Spring Boot system end to end—security, data, tests, and how we run it in production—so every answer ties to something I actually shipped, not generic framework definitions.


Pattern cheat sheet (quick reference)

Need Spring Boot starting point
REST API spring-boot-starter-web + @RestController
Database access spring-boot-starter-data-jpa + Flyway
Validation spring-boot-starter-validation + @Valid
Security spring-boot-starter-security + OAuth2 resource server
Testing @WebMvcTest, @DataJpaTest, Testcontainers
Production ops spring-boot-starter-actuator + Micrometer
Caching @EnableCaching + Caffeine or Redis
Async / I/O scale Virtual threads on Java 21
Microservices edge Spring Cloud Gateway + Config (or K8s native)
Resilience Resilience4j circuit breaker

References

Official Spring documentation

On-site prep


Summary

Experienced Spring Boot interviews test auto-configuration, JPA and transactions, security, testing, and production operability—not annotation trivia. Answer aloud and compare your structure to each section. Pair with Java part 1 and part 2, full stack interviews, and SQL interviews when persistence becomes execution plans.

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …