Interviews

🎯 Interview Guides 12 guides · updated 2026

Real questions and structured answers for data, cloud, and AI engineering interviews β€” including the system-design and GenAI rounds now showing up everywhere.

Spring Boot Interview Questions and Answers

These questions cover Spring Boot’s core features and advanced patterns β€” what’s tested for Java backend engineer, microservices developer, and enterprise application architect roles.


Core Spring Boot

Q1. What is Spring Boot and how does it differ from Spring Framework?

Spring Framework is a comprehensive dependency injection and programming model β€” but it requires significant XML or Java configuration to set up a working application.

Spring Boot is an opinionated layer on top of Spring Framework that:

// Spring Boot: zero XML, start in seconds
@SpringBootApplication // = @Configuration + @EnableAutoConfiguration + @ComponentScan
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
// Run with: java -jar order-service.jar
// Embedded Tomcat starts on port 8080 automatically

Q2. How does Spring Boot auto-configuration work?

Auto-configuration uses @Conditional annotations to configure beans only when certain conditions are met:

// Spring Boot's auto-configuration for DataSource (simplified)
@Configuration
@ConditionalOnClass(DataSource.class) // Only if DataSource is on classpath
@ConditionalOnMissingBean(DataSource.class) // Only if no DataSource bean already exists
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnProperty(name = "spring.datasource.url")
public DataSource dataSource(DataSourceProperties props) {
return DataSourceBuilder.create()
.url(props.getUrl())
.username(props.getUsername())
.password(props.getPassword())
.build();
}
}

All auto-configurations are listed in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. When you add spring-boot-starter-data-jpa, Spring Boot auto-configures DataSource, EntityManagerFactory, and TransactionManager automatically.

Debug auto-configuration: spring.autoconfigure.report=true or run with --debug flag.


Q3. What is the Spring IoC container and dependency injection?

The IoC (Inversion of Control) container manages bean creation, lifecycle, and dependency wiring. Instead of creating dependencies yourself, you declare them and Spring injects them:

// Service layer
@Service
public class OrderService {
private final OrderRepository orderRepo;
private final PaymentClient paymentClient;
private final EmailService emailService;
// Constructor injection β€” preferred (makes dependencies explicit, testable)
public OrderService(OrderRepository orderRepo,
PaymentClient paymentClient,
EmailService emailService) {
this.orderRepo = orderRepo;
this.paymentClient = paymentClient;
this.emailService = emailService;
}
@Transactional
public Order placeOrder(OrderRequest request) {
Order order = orderRepo.save(new Order(request));
paymentClient.charge(order.getTotal(), request.getPaymentMethod());
emailService.sendConfirmation(order);
return order;
}
}
// Spring creates and wires this automatically
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerIdAndStatus(Long customerId, OrderStatus status);
Optional<Order> findByOrderNumber(String orderNumber);
}

Injection types: Constructor injection (best), setter injection, field injection (@Autowired on field β€” avoid, untestable).


REST APIs

Q4. How do you build a REST API with Spring Boot?

@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@GetMapping
public ResponseEntity<Page<OrderDto>> listOrders(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) OrderStatus status) {
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
return ResponseEntity.ok(orderService.findOrders(status, pageable));
}
@GetMapping("/{id}")
public ResponseEntity<OrderDto> getOrder(@PathVariable Long id) {
return orderService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
public ResponseEntity<OrderDto> createOrder(
@Valid @RequestBody CreateOrderRequest request) {
OrderDto created = orderService.create(request);
URI location = URI.create("/api/v1/orders/" + created.getId());
return ResponseEntity.created(location).body(created);
}
@PatchMapping("/{id}/status")
public ResponseEntity<OrderDto> updateStatus(
@PathVariable Long id,
@RequestBody UpdateStatusRequest request) {
return ResponseEntity.ok(orderService.updateStatus(id, request.getStatus()));
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteOrder(@PathVariable Long id) {
orderService.delete(id);
}
}

Q5. How do you handle exceptions in a Spring Boot REST API?

// Global exception handler
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
Map<String, String> errors = ex.getBindingResult().getFieldErrors().stream()
.collect(Collectors.toMap(
FieldError::getField,
fe -> fe.getDefaultMessage() != null ? fe.getDefaultMessage() : "invalid"
));
return ResponseEntity.badRequest()
.body(new ErrorResponse("VALIDATION_FAILED", "Validation failed", errors));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleUnexpected(Exception ex) {
log.error("Unexpected error", ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred"));
}
}
// Custom exception
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String resourceName, Long id) {
super(resourceName + " not found with id: " + id);
}
}

Data Access

Q6. How does Spring Data JPA work and what is the JPA entity lifecycle?

@Entity
@Table(name = "orders")
@EntityListeners(AuditingEntityListener.class)
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String orderNumber;
@ManyToOne(fetch = FetchType.LAZY) // LAZY avoids N+1
@JoinColumn(name = "customer_id")
private Customer customer;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
@Enumerated(EnumType.STRING)
private OrderStatus status;
@CreatedDate
private Instant createdAt;
@LastModifiedDate
private Instant updatedAt;
}
// Repository β€” Spring Data generates implementations automatically
public interface OrderRepository extends JpaRepository<Order, Long> {
// Method name parsing
List<Order> findByStatusAndCreatedAtAfter(OrderStatus status, Instant since);
// JPQL
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.customer.id = :customerId")
List<Order> findWithItemsByCustomerId(@Param("customerId") Long customerId);
// Native SQL
@Query(value = "SELECT * FROM orders WHERE status = ?1 LIMIT ?2",
nativeQuery = true)
List<Order> findTopByStatus(String status, int limit);
// Projections β€” select fewer columns
@Query("SELECT o.orderNumber as orderNumber, o.status as status FROM Order o")
List<OrderSummary> findAllSummaries();
}

JPA entity lifecycle: Transient (new, not tracked) β†’ Managed (tracked by EntityManager) β†’ Detached (after transaction ends) β†’ Removed (marked for deletion).


Q7. How do you avoid the N+1 query problem in Spring Data JPA?

N+1 happens when loading N entities triggers N additional queries for their lazy-loaded associations:

// Problem: fetching 100 orders β†’ 100 extra queries for customer
List<Order> orders = orderRepo.findAll();
orders.forEach(o -> System.out.println(o.getCustomer().getName())); // N+1!
// Solution 1: JOIN FETCH in JPQL
@Query("SELECT DISTINCT o FROM Order o JOIN FETCH o.customer JOIN FETCH o.items")
List<Order> findAllWithDetails();
// Solution 2: Entity graph
@EntityGraph(attributePaths = {"customer", "items"})
List<Order> findByStatus(OrderStatus status);
// Solution 3: Batch fetching (Hibernate property)
# application.properties
spring.jpa.properties.hibernate.default_batch_fetch_size=20
// Solution 4: Use Blaze-Persistence or DTO projections
// to avoid fetching entities at all when you only need specific fields

Security

Q8. How do you implement JWT authentication in Spring Boot?

@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final JwtAuthFilter jwtAuthFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // Disabled for stateless APIs
.sessionManagement(sm -> sm.sessionCreationPolicy(STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/actuator/health").permitAll()
.requestMatchers(HttpMethod.GET, "/api/v1/products/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
final String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
String jwt = authHeader.substring(7);
String username = jwtService.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails user = userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwt, user)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
chain.doFilter(request, response);
}
}

Microservices & Configuration

Q9. What is Spring Boot Actuator and what does it provide?

Actuator exposes production-ready HTTP endpoints for monitoring and management:

application.yml
management:
endpoints:
web:
exposure:
include: health, info, metrics, prometheus, loggers, env
base-path: /actuator
endpoint:
health:
show-details: when_authorized
metrics:
export:
prometheus:
enabled: true

Key endpoints:

// Custom health indicator
@Component
public class ExternalApiHealthIndicator implements HealthIndicator {
private final ExternalApiClient client;
@Override
public Health health() {
try {
client.ping();
return Health.up().withDetail("api", "available").build();
} catch (Exception ex) {
return Health.down().withDetail("api", "unavailable").withException(ex).build();
}
}
}

Q10. How do you externalize configuration in Spring Boot?

application.yml
app:
payment:
provider: stripe
timeout-ms: 5000
retry:
max-attempts: 3
backoff-ms: 1000
feature-flags:
new-checkout: false
// Typed configuration class
@ConfigurationProperties(prefix = "app.payment")
@Validated
public record PaymentConfig(
@NotBlank String provider,
@Positive int timeoutMs,
RetryConfig retry
) {
public record RetryConfig(@Positive int maxAttempts, @Positive int backoffMs) {}
}
// Enable in main app or @Configuration class
@SpringBootApplication
@EnableConfigurationProperties(PaymentConfig.class)
public class App { ... }
// Use it
@Service
@RequiredArgsConstructor
public class PaymentService {
private final PaymentConfig config;
public void charge(BigDecimal amount) {
// config.timeoutMs(), config.retry().maxAttempts()
}
}

Configuration priority (highest to lowest):

  1. Command-line arguments (--server.port=9090)
  2. Environment variables (SERVER_PORT=9090)
  3. application-{profile}.yml
  4. application.yml
  5. Default values in @ConfigurationProperties

Testing

Q11. How do you write integration tests in Spring Boot?

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Testcontainers
class OrderControllerIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16")
.withDatabaseName("testdb");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private OrderRepository orderRepository;
@Test
void createOrder_returnsCreatedWithLocation() {
var request = new CreateOrderRequest("PROD-123", 2, "customer@example.com");
var response = restTemplate.postForEntity("/api/v1/orders", request, OrderDto.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(response.getHeaders().getLocation()).isNotNull();
assertThat(response.getBody().getStatus()).isEqualTo("PENDING");
assertThat(orderRepository.count()).isEqualTo(1);
}
}
// Slice test β€” only web layer
@WebMvcTest(OrderController.class)
class OrderControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private OrderService orderService;
@Test
void getOrder_notFound_returns404() throws Exception {
when(orderService.findById(99L)).thenReturn(Optional.empty());
mockMvc.perform(get("/api/v1/orders/99"))
.andExpect(status().isNotFound());
}
}

Q12. What are the key features introduced in Spring Boot 3.x?

Spring Boot 3.0 (2022):

Spring Boot 3.2 (2023):

Spring Boot 3.3 / 3.4 (2024–2025):

// RestClient (Spring Boot 3.2+ β€” replaces RestTemplate)
@Bean
RestClient orderClient(RestClient.Builder builder) {
return builder.baseUrl("https://api.example.com").build();
}
// Usage
OrderDto order = restClient.get()
.uri("/orders/{id}", orderId)
.retrieve()
.body(OrderDto.class);
// Virtual threads (Spring Boot 3.2+)
// application.properties:
# spring.threads.virtual.enabled=true
# All web requests now handled by virtual threads automatically