Spring Boot

Practice commonly asked Spring Boot interview questions with clear answers and explanations.

30 Interview Questions

Spring Boot Interview Questions

30 Questions
Q 1

What is the difference between spring-boot-starter-parent and importing spring-boot-dependencies in dependencyManagement?

Medium
Answer
spring-boot-starter-parent provides default Maven plugin configurations, resource filtering, UTF-8 defaults, and dependency version management via parent inheritance. Importing spring-boot-dependencies with <scope>import</scope> inside <dependencyManagement> provides only version management without forcing parent POM inheritance, allowing projects to keep their own corporate parent POM.
Explanation
Use dependencyManagement import (BOM) when your company already has a custom base parent POM.
Code Example Java
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
Reference: Spring Boot
Q 2

How do you implement API Versioning in Spring Boot REST APIs?

Medium
Answer
Common versioning strategies: 1. URI Path Versioning (/api/v1/users), 2. Query Parameter Versioning (/api/users?version=1), 3. Custom Header Versioning (X-API-Version: 1), and 4. Content Negotiation / Media Type Versioning (Accept: application/vnd.company.v1+json).
Explanation
URI Path Versioning is the most prevalent and cache-friendly approach in modern REST API design.
Code Example Java
@RestController
@RequestMapping("/api/v1/orders") // URI Versioning
public class OrderV1Controller {}

@RestController
@RequestMapping("/api/v2/orders") // URI Versioning
public class OrderV2Controller {}
Reference: Spring Boot
Q 3

What is the difference between Session Authentication and Stateless Token Authentication in Spring Boot Web Apps?

Medium
Answer
Session authentication stores user authentication state in server memory (JSESSIONID cookie), requiring sticky sessions or Redis session replication (Spring Session) in clustered deployments. Stateless token authentication (JWT) validates digitally signed tokens with every request, eliminating server session storage and simplifying horizontal scaling.
Explanation
Use Spring Session with Redis when stateful session features are required across multi-pod Kubernetes clusters.
Code Example Java
<!-- Spring Session Redis Starter -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
Reference: Spring Boot
Q 4

What is the role of Flyway Baseline and Repair commands in Spring Boot schema migrations?

Hard
Answer
flyway.baseline-on-migrate=true creates a baseline entry in flyway_schema_history for existing legacy non-empty databases without failing. flyway.repair fixes checksum mismatch errors when migration script headers or metadata have been modified after execution.
Explanation
Flyway strictly verifies migration script checksums; modifying an already-applied SQL migration script will fail startup unless repaired.
Code Example Java
# application.properties
spring.flyway.baseline-on-migrate=true
spring.flyway.baseline-version=1
Reference: Spring Boot
Q 5

What is the difference between @SneakyThrows and standard Exception Handling in Spring Boot?

Easy
Answer
@SneakyThrows (Lombok) bypasses Java's compile-time checked exception checks by sneakily throwing checked exceptions without declaring them in the method 'throws' clause. In Spring Boot, standard global exception handling (@RestControllerAdvice) should still be used to catch and map these exceptions to HTTP status codes.
Explanation
@SneakyThrows tricks the compiler via bytecode type erasure but does not convert the exception into a RuntimeException at runtime.
Code Example Java
@SneakyThrows // Avoids declaring 'throws IOException' on method signature
public String readFile(String path) {
    return Files.readString(Path.of(path));
}
Reference: Spring Boot
Q 6

How do you mask sensitive data in Spring Boot logs (Logback / Log4j2)?

Medium
Answer
Sensitive data (passwords, credit card numbers, PII) is masked using custom Logback PatternLayout / CompositeConverter rules that apply regular expressions to replace matching patterns with asterisks before writing to log streams.
Explanation
Never rely solely on developers omitting sensitive fields in toString(); enforce logging sanitizers at the layout converter level.
Code Example Java
<!-- logback-spring.xml -->
<conversionRule conversionWord="maskedMsg" 
                converterClass="com.example.logging.MaskingPatternConverter" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %maskedMsg%n</pattern>
    </encoder>
</appender>
Reference: Spring Boot
Q 7

What is the Saga Pattern in Spring Boot microservices and how does Orchestration differ from Choreography?

Hard
Answer
The Saga pattern manages distributed transactions across microservices as a sequence of local transactions, executing compensating transactions if a step fails. Choreography coordinates events implicitly via message brokers (Kafka/RabbitMQ). Orchestration uses a central orchestrator service to explicitly command each participant.
Explanation
Choreography is simple for small flows; Orchestration is preferred for complex multi-step enterprise business transactions.
Code Example Java
// Compensating transaction triggered if payment fails:
public void compensateOrder(Long orderId) {
    orderRepository.updateStatus(orderId, OrderStatus.CANCELLED);
    inventoryService.releaseStock(orderId);
}
Reference: Spring Boot
Q 8

What is the difference between Spring Cloud Config Server and Spring Boot externalized configuration?

Medium
Answer
Spring Boot externalized config reads properties from local files or environment variables at startup. Spring Cloud Config Server centralizes external configuration for all microservices in a central Git repository, supporting dynamic runtime property reloads via @RefreshScope and /actuator/refresh without restarting containers.
Explanation
@RefreshScope rebuilds the target bean instance dynamically when new configuration is pushed from Config Server.
Code Example Java
@RestController
@RefreshScope // Reloads property dynamically on /actuator/refresh
public class FeatureFlagController {
    @Value("${feature.new-ui:false}")
    private boolean newUiEnabled;
}
Reference: Spring Boot
Q 9

How do you handle Database Transactions across Multiple DataSources in Spring Boot (ChainedTransactionManager / JTA)?

Hard
Answer
For 2-Phase Commit (2PC) distributed transactions across multiple databases, configure a JTA transaction manager (such as Atomikos or Narayana). For simpler multi-datasource setups without true 2PC, configure separate dedicated PlatformTransactionManager beans and specify the transaction manager in @Transactional("db2TransactionManager").
Explanation
Specifying the transactionManager bean name in @Transactional directs the commit/rollback lifecycle to the intended database.
Code Example Java
@Transactional("primaryTransactionManager")
public void savePrimary(Order order) { primaryRepo.save(order); }

@Transactional("secondaryTransactionManager")
public void saveAudit(AuditLog log) { auditRepo.save(log); }
Reference: Spring Boot
Q 10

What is Spring Boot Admin and how does it monitor microservice clusters?

Medium
Answer
Spring Boot Admin is a community management UI that registers and monitors Spring Boot Actuator endpoints across multiple client microservices, visualizing health status, JVM memory graphs, thread dumps, loggers, and notification alerts.
Explanation
Client applications register with Spring Boot Admin Server either via Spring Cloud Discovery (Eureka/Consul) or spring-boot-admin-starter-client.
Code Example Java
<!-- Spring Boot Admin Client -->
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
    <version>3.2.0</version>
</dependency>
Reference: Spring Boot
Q 11

What is the difference between Lazy Initialization in Spring Boot (spring.main.lazy-initialization=true) vs default eager loading?

Medium
Answer
By default, Spring Boot eagerly creates all singleton beans at startup, catching configuration errors immediately. Setting spring.main.lazy-initialization=true defers bean creation until the bean is first requested, reducing startup time during local development but delaying error detection until runtime.
Explanation
Lazy initialization is beneficial for fast local developer restarts and serverless function cold starts, but risky for production.
Code Example Java
# application-dev.properties
spring.main.lazy-initialization=true
Reference: Spring Boot
Q 12

What is the difference between ApplicationRunner and CommandLineRunner in Spring Boot?

Easy
Answer
Both interfaces provide a run() method executed once immediately after the Spring ApplicationContext is fully initialized. CommandLineRunner receives raw String[] arguments. ApplicationRunner receives parsed ApplicationArguments providing structured access to option arguments (--key=value) and non-option arguments.
Explanation
Multiple runners can be ordered using the @Order annotation to execute database seeders or warmup tasks sequentially.
Code Example Java
@Component
@Order(1)
public class DatabaseSeeder implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) {
        if (args.containsOption("seed")) {
            System.out.println("Seeding initial admin user data...");
        }
    }
}
Reference: Spring Boot
Q 13

How do you configure and secure HTTP Security Headers in Spring Boot with Spring Security?

Medium
Answer
Spring Security automatically adds standard security headers by default (X-Content-Type-Options: nosniff, X-Frame-Options: DENY, X-XSS-Protection, Cache-Control). Custom headers like Content-Security-Policy (CSP) and HSTS are configured inside the SecurityFilterChain headers DSL.
Explanation
Content Security Policy (CSP) prevents cross-site scripting (XSS) and data injection attacks by restricting script origins.
Code Example Java
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .headers(headers -> headers
            .contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'"))
            .frameOptions(HeadersConfigurer.FrameOptionsConfig::deny)
        )
        .build();
}
Reference: Spring Boot
Q 14

What is the difference between @JsonIgnore, @JsonProperty, and @JsonInclude in Jackson Spring Boot?

Easy
Answer
@JsonIgnore excludes a field from both serialization and deserialization. @JsonProperty defines a custom JSON key name or specifies access permissions (READ_ONLY/WRITE_ONLY). @JsonInclude(Include.NON_NULL) excludes fields with null values from the serialized JSON output.
Explanation
@JsonProperty(access = Access.WRITE_ONLY) is ideal for passwords so they can be accepted on registration but never leaked in response JSON.
Code Example Java
public class UserDTO {
    @JsonProperty("full_name")
    private String fullName;

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password; // Never serialized in responses

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String middleName;
}
Reference: Spring Boot
Q 15

How does Rate Limiting work in Spring Boot using Bucket4j?

Hard
Answer
Bucket4j implements the Token Bucket algorithm. When a request arrives, the application attempts to consume a token from the bucket; if tokens are available, the request proceeds. If the bucket is empty, the filter returns HTTP 429 Too Many Requests.
Explanation
Bucket4j can be backed by Redis for distributed rate-limiting across multi-instance microservice clusters.
Code Example Java
Bandwidth limit = Bandwidth.classic(10, Refill.greedy(10, Duration.ofMinutes(1)));
Bucket bucket = Bucket.builder().addLimit(limit).build();

if (bucket.tryConsume(1)) {
    // Allow request to proceed
} else {
    res.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
}
Reference: Spring Boot
Q 16

What is the Spring Boot Maven Plugin and how does 'mvn spring-boot:run' differ from 'java -jar app.jar'?

Easy
Answer
mvn spring-boot:run executes the application directly from compiled class files on the local filesystem without creating an archive. java -jar app.jar executes the packaged, standalone fat JAR using Spring Boot's custom JarLauncher classloader.
Explanation
The repackage goal of spring-boot-maven-plugin transforms standard Maven JARs into executable fat JARs with embedded dependencies.
Code Example Java
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
Reference: Spring Boot
Q 17

What is the difference between @Async with ThreadPoolTaskExecutor vs default SimpleAsyncTaskExecutor?

Medium
Answer
If no custom TaskExecutor is configured, Spring defaults to SimpleAsyncTaskExecutor which does NOT reuse threads—it spawns a brand-new OS thread for every single task, leading to thread exhaustion. Configuring a ThreadPoolTaskExecutor limits and reuses pooled threads.
Explanation
Always declare a ThreadPoolTaskExecutor bean named 'taskExecutor' to override the default.
Code Example Java
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(10);
    executor.setQueueCapacity(100);
    executor.setThreadNamePrefix("AsyncWorker-");
    executor.initialize();
    return executor;
}
Reference: Spring Boot
Q 18

What is Idempotency in REST APIs and how is it implemented in Spring Boot?

Hard
Answer
Idempotency guarantees that executing an identical request multiple times produces the exact same outcome as executing it once (e.g. preventing double credit card charges on network retries). It is implemented using an Idempotency-Key header stored in Redis with an atomic SETNX lock.
Explanation
If an incoming request presents an Idempotency-Key that already exists in Redis, the server returns the cached prior response immediately.
Code Example Java
@Component
public class IdempotencyInterceptor implements HandlerInterceptor {
    @Autowired private StringRedisTemplate redisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        String key = req.getHeader("Idempotency-Key");
        if (key != null) {
            Boolean isNew = redisTemplate.opsForValue().setIfAbsent("idemp:" + key, "PENDING", Duration.ofMinutes(5));
            if (Boolean.FALSE.equals(isNew)) throw new DuplicateRequestException("Duplicate request");
        }
        return true;
    }
}
Reference: Spring Boot
Q 19

How does Spring Boot support Distributed Caching with Redis (spring-boot-starter-data-redis)?

Medium
Answer
Adding spring-boot-starter-data-redis and @EnableCaching configures a RedisCacheManager. @Cacheable, @CachePut, and @CacheEvict serialize method return objects as JSON or binary into Redis keys with configurable Time-To-Live (TTL).
Explanation
Configure RedisCacheConfiguration with GenericJackson2JsonRedisSerializer for human-readable JSON values in Redis.
Code Example Java
@Bean
public RedisCacheConfiguration cacheConfiguration() {
    return RedisCacheConfiguration.defaultCacheConfig()
        .entryTtl(Duration.ofMinutes(10))
        .disableCachingNullValues()
        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
Reference: Spring Boot
Q 20

What are Projections in Spring Data JPA and what is the difference between Interface-based and DTO-based projections?

Medium
Answer
Projections retrieve only specific subset columns from database tables instead of loading entire managed entity graphs. Interface-based projections use getter interfaces (backed by Spring proxies). DTO projections use Java Records or POJOs with constructor expressions for maximum performance.
Explanation
DTO-based Record projections avoid Spring proxy creation overhead and produce clean, immutable data carriers.
Code Example Java
// DTO Record Projection:
public record UserSummaryDTO(Long id, String username, String email) {}

public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT new com.example.dto.UserSummaryDTO(u.id, u.username, u.email) FROM User u")
    List<UserSummaryDTO> findAllSummaries();
}
Reference: Spring Boot
Q 21

What is the Open Session in View (OSIV) anti-pattern in Spring Boot and why is it warned by default?

Hard
Answer
OSIV keeps the Hibernate database session and connection open throughout the entire HTTP request lifecycle (including controller and view rendering). While it prevents LazyInitializationException, it exhausts database connection pools under high traffic and allows uncontrolled queries inside controllers/views.
Explanation
Best practice is to disable OSIV (spring.jpa.open-in-view=false) and fetch required associations explicitly in service transactions using DTO projections or JOIN FETCH.
Code Example Java
# Recommended production setting:
spring.jpa.open-in-view=false
Reference: Spring Boot
Q 22

What are Optimistic Locking and Pessimistic Locking in Spring Data JPA?

Hard
Answer
Optimistic Locking uses a @Version column (number or timestamp) to detect concurrent modifications on commit, throwing ObjectOptimisticLockingFailureException if the version changed. Pessimistic Locking acquires physical database row locks (SELECT ... FOR UPDATE via @Lock(LockModeType.PESSIMISTIC_WRITE)).
Explanation
Use Optimistic Locking for low-contention high-read architectures; use Pessimistic Locking for high-contention financial balance deductions.
Code Example Java
public interface AccountRepository extends JpaRepository<Account, Long> {
    // Pessimistic row-level lock (SELECT FOR UPDATE):
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("SELECT a FROM Account a WHERE a.id = :id")
    Optional<Account> findByIdForUpdate(@Param("id") Long id);
}
Reference: Spring Boot
Q 23

What is the difference between JPA save(), saveAndFlush(), and persist() in Spring Data?

Hard
Answer
save() adds an entity to the persistence context and defers the SQL INSERT/UPDATE until transaction commit. saveAndFlush() writes changes to the database immediately in the current transaction without waiting for commit. persist() is an EntityManager method that strictly handles new entities.
Explanation
saveAndFlush() does NOT commit the transaction; it only synchronizes the persistence context state with the underlying database session.
Code Example Java
@Transactional
public void createUser(User user) {
    userRepository.save(user); // SQL statement deferred until transaction commit
    userRepository.saveAndFlush(user); // Flushes SQL INSERT immediately to DB
}
Reference: Spring Boot
Q 24

How do you create Custom Metrics in Spring Boot using Micrometer MeterRegistry?

Medium
Answer
Inject Micrometer's MeterRegistry bean and register custom Counter, Timer, or Gauge instances to record business events and export them to Prometheus, Datadog, or Grafana via /actuator/prometheus.
Explanation
Counters measure incrementing event counts; Timers measure both duration and rate.
Code Example Java
@Service
public class PaymentService {
    private final Counter orderCounter;
    public PaymentService(MeterRegistry registry) {
        this.orderCounter = registry.counter("orders.completed.total", "type", "credit_card");
    }
    public void processPayment() {
        // Business logic
        orderCounter.increment();
    }
}
Reference: Spring Boot
Q 25

How does Spring Boot Actuator support Custom Health Indicators?

Medium
Answer
Implement the HealthIndicator interface and override the health() method, returning Health.up() with custom metadata details or Health.down(exception) to report service degradation on the /actuator/health endpoint.
Explanation
Spring Boot aggregates all registered HealthIndicator beans to compute the overall system status.
Code Example Java
@Component
public class PaymentGatewayHealthIndicator implements HealthIndicator {
    @Override
    public Health health() {
        boolean reachable = checkGatewayConnection();
        if (reachable) {
            return Health.up().withDetail("latency", "25ms").build();
        }
        return Health.down().withDetail("error", "Timeout connecting to gateway").build();
    }
}
Reference: Spring Boot
Q 26

What is the role of KafkaTemplate and @KafkaListener in Spring Boot Kafka integration?

Medium
Answer
spring-kafka provides KafkaTemplate for producing and sending messages to Kafka topics asynchronously (returning a CompletableFuture<SendResult>), and @KafkaListener for declarative consumer message consumption across consumer groups.
Explanation
Spring Boot auto-configures KafkaTemplate, producer/consumer factories, and concurrent message listener containers based on spring.kafka properties.
Code Example Java
@Service
public class OrderEventService {
    @Autowired private KafkaTemplate<String, OrderEvent> kafkaTemplate;

    public void sendOrder(OrderEvent event) {
        kafkaTemplate.send("orders-topic", event.orderId(), event);
    }

    @KafkaListener(topics = "orders-topic", groupId = "billing-group")
    public void consumeOrder(OrderEvent event) {
        System.out.println("Processing billing for order: " + event.orderId());
    }
}
Reference: Spring Boot
Q 27

What is Resilience4j and how is Circuit Breaker implemented in Spring Boot microservices?

Hard
Answer
Resilience4j is a fault-tolerance library designed for functional Java. The @CircuitBreaker annotation monitors downstream failures; when failure rates exceed a threshold, the circuit transitions from CLOSED to OPEN, immediately short-circuiting calls and routing requests to a fallback method.
Explanation
The fallback method must have the exact same return type and argument list as the protected method, plus an additional Throwable parameter at the end.
Code Example Java
@Service
public class InventoryService {
    @CircuitBreaker(name = "inventoryService", fallbackMethod = "fallbackStock")
    public int checkStock(String productId) {
        return remoteWarehouseClient.getStock(productId); // Remote network call
    }
    public int fallbackStock(String productId, Throwable t) {
        return 0; // Safe default response during service outages
    }
}
Reference: Spring Boot
Q 28

How do you implement Stateless JWT Authentication in Spring Boot with Spring Security 6+?

Hard
Answer
Set SessionCreationPolicy to STATELESS in SecurityFilterChain, disable CSRF for stateless REST APIs, add a custom OncePerRequestFilter before UsernamePasswordAuthenticationFilter to extract and validate JWT tokens, and populate the SecurityContextHolder with an authenticated UsernamePasswordAuthenticationToken.
Explanation
SecurityContextHolder.getContext().setAuthentication(auth) tells Spring Security that the request is authenticated for the remainder of the filter chain.
Code Example Java
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, JwtAuthFilter jwtFilter) throws Exception {
    return http
        .csrf(AbstractHttpConfigurer::disable)
        .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .authorizeHttpRequests(a -> a
            .requestMatchers("/api/auth/**").permitAll()
            .anyRequest().authenticated())
        .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
        .build();
}
Reference: Spring Boot
Q 29

How does Spring Boot handle CORS (Cross-Origin Resource Sharing)?

Easy
Answer
CORS can be configured at the controller/method level using @CrossOrigin, or globally across the application by registering a WebMvcConfigurer bean overriding addCorsMappings().
Explanation
For Spring Security-protected applications, CORS must also be explicitly enabled inside the SecurityFilterChain (http.cors(Customizer.withDefaults())).
Code Example Java
@Configuration
public class WebCorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("https://app.example.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true);
    }
}
Reference: Spring Boot
Q 30

What is the difference between RestTemplate, WebClient, and RestClient in Spring Boot 3+?

Hard
Answer
RestTemplate is the legacy synchronous, blocking HTTP client (in maintenance mode). WebClient (from spring-boot-starter-webflux) is a reactive, non-blocking HTTP client supporting streaming. RestClient (introduced in Spring Boot 3.2+) is the modern synchronous HTTP client offering a fluent, functional API identical to WebClient without requiring reactive dependencies.
Explanation
RestClient is recommended for standard synchronous HTTP requests in modern Spring Boot 3.2+ applications.
Code Example Java
// Modern RestClient (Spring Boot 3.2+):
RestClient restClient = RestClient.create();
User user = restClient.get()
    .uri("https://api.example.com/users/{id}", 1)
    .accept(MediaType.APPLICATION_JSON)
    .retrieve()
    .body(User.class);
Reference: Spring Boot

About This Topic

Prepare for Spring Boot interviews with important concepts and commonly asked questions.