Spring Boot Interview Questions 2026

Top 60 Questions & Answers — From Basics to Senior Level

This guide covers the most commonly asked Spring Boot interview questions in 2026 — from basic concepts tested at junior level to advanced architecture questions at senior/lead level. Each answer is written to be concise enough to deliver in an interview while complete enough to actually demonstrate understanding.

How to use this guide: Click any question to expand the answer. Questions marked Easy suit 0–2 year roles, Medium for 3–5 years, Hard for senior/lead roles.
Core Concepts & Auto-Configuration
1
What is Spring Boot and how does it differ from the Spring Framework?Easy

The Spring Framework is a comprehensive Java application framework that provides dependency injection, AOP, transaction management and more. It is powerful but requires significant XML or annotation-based configuration to wire everything together.

Spring Boot is built on top of Spring Framework and removes that setup burden by providing:

  • Auto-configuration — detects libraries on the classpath and configures them automatically.
  • Starter dependencies — curated POM/Gradle bundles (e.g. spring-boot-starter-web) that pull in everything needed for a feature.
  • Embedded server — Tomcat, Jetty or Undertow bundled inside the JAR; no separate server install needed.
  • Opinionated defaults — sensible defaults that work for most apps out of the box.
Interview tip: say "Spring Boot is not a replacement for Spring — it is an opinionated wrapper around it that eliminates boilerplate setup."
2
How does Spring Boot auto-configuration work internally?Medium

Auto-configuration is driven by the @EnableAutoConfiguration annotation (included inside @SpringBootApplication). Here is the internal flow:

  1. Spring Boot reads META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (Spring Boot 3) — a list of auto-configuration classes.
  2. Each class is annotated with @ConditionalOn* annotations — e.g. @ConditionalOnClass(DataSource.class) only applies if a DataSource class is on the classpath.
  3. If the conditions pass, Spring registers the beans defined in that configuration class.
// Example from DataSourceAutoConfiguration (simplified)
@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
public class DataSourceAutoConfiguration {
    @Bean
    public DataSource dataSource(DataSourceProperties props) {
        return props.initializeDataSourceBuilder().build();
    }
}

@ConditionalOnMissingBean ensures your own @Bean definition takes precedence — auto-configuration only fires when you have not provided your own.

3
What does @SpringBootApplication do? Can you break it down?Easy

@SpringBootApplication is a meta-annotation that combines three annotations:

  • @Configuration — marks the class as a source of Spring bean definitions.
  • @EnableAutoConfiguration — triggers Spring Boot's auto-configuration mechanism.
  • @ComponentScan — scans the current package and sub-packages for components, services, repositories etc.
@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}
You can exclude specific auto-configurations: @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
4
What is the difference between @Component, @Service, @Repository, and @Controller?Easy

All four are specialisations of @Component and result in Spring registering the class as a bean. The difference is semantic and enables tooling and additional behaviour:

  • @Component — generic stereotype. Use when none of the others fit.
  • @Service — marks business logic layer. No extra behaviour; signals intent.
  • @Repository — marks persistence layer. Spring adds automatic exception translation — Spring Data exceptions are translated to DataAccessException hierarchy.
  • @Controller — marks a web MVC controller. Works with @RequestMapping to handle HTTP requests and return views.
  • @RestController@Controller + @ResponseBody. All handler methods return JSON/XML directly.
5
What are Spring Boot Starters? Name five common ones.Easy

Starters are pre-packaged dependency descriptors that bundle all the libraries needed for a feature. You add one dependency and Spring Boot pulls in everything automatically.

  • spring-boot-starter-web — Spring MVC, embedded Tomcat, Jackson for JSON.
  • spring-boot-starter-data-jpa — Spring Data JPA, Hibernate, transaction support.
  • spring-boot-starter-security — Spring Security with sensible defaults.
  • spring-boot-starter-test — JUnit 5, Mockito, AssertJ, Spring Test.
  • spring-boot-starter-actuator — health checks, metrics, info endpoints.
  • spring-boot-starter-validation — Bean Validation (Hibernate Validator).
6
How do you configure Spring Boot? What is the order of property resolution?Medium

Spring Boot reads configuration from multiple sources in a defined order (higher number = higher priority):

  1. Default properties in SpringApplication
  2. application.properties / application.yml inside the JAR
  3. application-{profile}.properties inside the JAR
  4. application.properties outside the JAR (same directory)
  5. OS environment variables
  6. JVM system properties (-Dmy.prop=value)
  7. Command-line arguments (--my.prop=value)

Command-line arguments override everything. This lets you override database URLs or secrets at deploy time without rebuilding.

7
What are Spring Profiles and how do you use them?Easy

Profiles let you define environment-specific configuration. You create profile-specific property files:

application-dev.properties    # H2 in-memory DB
application-prod.properties   # PostgreSQL connection

Activate a profile at startup:

# Via command line
java -jar app.jar --spring.profiles.active=prod

# Via environment variable
SPRING_PROFILES_ACTIVE=prod

You can also annotate beans to only load in certain profiles:

@Bean
@Profile("dev")
public DataSource devDataSource() { ... }
8
What is the difference between @Value and @ConfigurationProperties?Medium

@Value injects individual property values:

@Value("${app.timeout}")
private int timeout;

@ConfigurationProperties maps a group of related properties to a typed POJO — much better for structured config:

@ConfigurationProperties(prefix = "app")
@Component
public class AppProperties {
    private int timeout;
    private String apiUrl;
    // getters and setters
}

Prefer @ConfigurationProperties for anything beyond one or two properties — it gives you type safety, IDE autocompletion and validation with @Validated.

9
What are the different bean scopes in Spring?Medium
  • singleton (default) — one instance per Spring container. Shared across all requests.
  • prototype — new instance created every time the bean is requested.
  • request — one instance per HTTP request. Web-aware contexts only.
  • session — one instance per HTTP session.
  • application — one instance per ServletContext.
  • websocket — one instance per WebSocket session.
Common trap: injecting a prototype bean into a singleton bean — the prototype only gets created once. Fix with ApplicationContext.getBean() or a scoped proxy.
10
What is Spring Boot DevTools and what does it provide?Easy

DevTools (spring-boot-devtools) is a development-time dependency that provides:

  • Automatic restart — restarts the application when classpath files change.
  • LiveReload — refreshes the browser automatically when resources change.
  • Relaxed caching — disables template caching (Thymeleaf, Freemarker) so changes show immediately.
  • H2 console — auto-enables the H2 web console when H2 is on the classpath.

DevTools is automatically excluded from production JARs — it only activates when running from an exploded build.

REST APIs & Spring MVC
11
What is the difference between @RequestMapping, @GetMapping, @PostMapping etc.?Easy

@RequestMapping is the generic annotation that maps any HTTP method:

@RequestMapping(value = "/users", method = RequestMethod.GET)

The shorthand annotations are composed meta-annotations that fix the HTTP method:

  • @GetMapping("/users") — GET requests
  • @PostMapping("/users") — POST requests
  • @PutMapping("/users/{id}") — PUT requests
  • @DeleteMapping("/users/{id}") — DELETE requests
  • @PatchMapping("/users/{id}") — PATCH requests

Prefer the shorthand annotations — they are more readable and intent is explicit.

12
What is the difference between @PathVariable and @RequestParam?Easy

@PathVariable extracts a value from the URL path itself:

// GET /users/42
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) { ... }

@RequestParam extracts a value from the query string:

// GET /users?page=2&size=10
@GetMapping("/users")
public List<User> getUsers(
    @RequestParam(defaultValue = "0") int page,
    @RequestParam(defaultValue = "20") int size) { ... }

Use @PathVariable for resource identifiers, @RequestParam for filters/pagination/optional params.

13
How does Spring Boot handle exceptions globally? What is @ControllerAdvice?Medium

@ControllerAdvice (or @RestControllerAdvice) is a class-level annotation that makes exception handler methods apply across all controllers:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
        return new ErrorResponse("NOT_FOUND", ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
        String message = ex.getBindingResult().getFieldErrors()
            .stream().map(FieldError::getDefaultMessage)
            .collect(Collectors.joining(", "));
        return new ErrorResponse("VALIDATION_FAILED", message);
    }
}
This keeps error handling out of your controllers and in one consistent place.
14
How do you validate request bodies in Spring Boot?Medium

Add spring-boot-starter-validation, then annotate your DTO fields and add @Valid in the controller:

public class CreateUserRequest {
    @NotBlank(message = "Name is required")
    private String name;

    @Email(message = "Invalid email address")
    private String email;

    @Min(value = 18, message = "Must be at least 18")
    private int age;
}

@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest req) {
    // if validation fails, MethodArgumentNotValidException is thrown automatically
    return ResponseEntity.status(201).body(userService.create(req));
}
15
What is ResponseEntity and when would you use it?Easy

ResponseEntity<T> gives you full control over the HTTP response — status code, headers and body:

// Return 201 Created with a Location header
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody CreateUserRequest req) {
    User user = userService.create(req);
    URI location = ServletUriComponentsBuilder.fromCurrentRequest()
        .path("/{id}").buildAndExpand(user.getId()).toUri();
    return ResponseEntity.created(location).body(user);
}

// Return 204 No Content on delete
@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
    userService.delete(id);
    return ResponseEntity.noContent().build();
}

Use it when you need to set a specific status code or add response headers. For simple reads that always return 200, returning the object directly is fine.

16
How do you configure CORS in Spring Boot?Medium

Three ways, from simple to full control:

1. Per-method annotation:

@CrossOrigin(origins = "https://myapp.com")
@GetMapping("/users")
public List<User> getUsers() { ... }

2. Global via WebMvcConfigurer (recommended):

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("https://myapp.com")
            .allowedMethods("GET","POST","PUT","DELETE")
            .allowCredentials(true);
    }
}

3. With Spring Security — configure CORS in the SecurityFilterChain and provide a CorsConfigurationSource bean.

17
What is content negotiation in Spring MVC?Medium

Content negotiation is how Spring decides what format to return (JSON, XML etc.) based on the client's Accept header.

// Client sends: Accept: application/xml
// Spring returns XML if jackson-dataformat-xml is on classpath

@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
    return userService.findById(id);  // Spring picks JSON or XML automatically
}

You can also force a format via URL extension (deprecated) or request parameter (?format=xml) if configured. Jackson handles JSON by default; add jackson-dataformat-xml for XML support.

18
What is the difference between @RequestBody and @ResponseBody?Easy
  • @RequestBody — on a method parameter. Tells Spring to deserialise the HTTP request body (JSON/XML) into a Java object using HttpMessageConverter.
  • @ResponseBody — on a method or class. Tells Spring to serialise the return value and write it directly to the HTTP response body instead of resolving a view.

@RestController combines @Controller + @ResponseBody, so you don't need @ResponseBody on every method in a REST controller.

Spring Data JPA & Hibernate
19
What is Spring Data JPA? How does it differ from plain JPA/Hibernate?Easy

JPA is the Java Persistence API specification. Hibernate is the most common JPA implementation. Both require you to write EntityManager code for queries.

Spring Data JPA sits on top and eliminates most of that boilerplate. You define an interface extending JpaRepository and Spring generates the implementation at runtime:

public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByEmailAndActiveTrue(String email);
    Page<User> findByDepartment(String dept, Pageable pageable);
    @Query("SELECT u FROM User u WHERE u.salary > :min")
    List<User> findHighEarners(@Param("min") BigDecimal min);
}

Method names like findByEmailAndActiveTrue are parsed by Spring Data to generate the correct JPQL automatically.

20
What is the difference between FetchType.LAZY and FetchType.EAGER?Medium
  • EAGER — related entities are loaded immediately with the parent in the same query (or an additional join). Simple but can cause performance problems if the related collection is large.
  • LAZY — related entities are loaded only when accessed. A proxy is used and the database is hit on first access. Default for @OneToMany and @ManyToMany.
@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
private List<OrderLine> lines;
LAZY can cause the N+1 problem — loading 100 orders then accessing each order's lines fires 101 queries. Fix with @EntityGraph or a JOIN FETCH query when you know you need the data.
21
What is the N+1 problem and how do you solve it?Hard

The N+1 problem occurs when fetching a list of N entities triggers N additional queries to load a related collection — one query for the list, then one per entity:

// 1 query: SELECT * FROM orders
List<Order> orders = orderRepository.findAll();
// N queries: SELECT * FROM order_lines WHERE order_id = ?
orders.forEach(o -> o.getLines().size()); // N+1 total

Solutions:

  1. JOIN FETCH in JPQL: SELECT o FROM Order o JOIN FETCH o.lines
  2. @EntityGraph on the repository method to specify eager loading for that query only.
  3. Batch fetching: @BatchSize(size = 50) on the collection.
  4. Use a DTO projection with a constructor query to fetch only what you need.
22
What is @Transactional and how does it work?Medium

@Transactional wraps a method in a database transaction. Spring creates an AOP proxy around the method; the transaction starts before execution and commits on success or rolls back on a runtime exception.

@Service
public class OrderService {
    @Transactional
    public Order placeOrder(OrderRequest req) {
        Order order = orderRepository.save(new Order(req));
        inventoryService.deduct(req.getItems()); // same transaction
        paymentService.charge(req);              // same transaction
        return order;
        // commits here — all three operations commit together
    }
}

Key attributes: propagation (REQUIRED, REQUIRES_NEW etc.), isolation level, rollbackFor, readOnly = true (performance hint for SELECT-only methods).

@Transactional only works on public methods called from outside the bean — self-invocation bypasses the proxy.
23
What is the difference between save() and saveAndFlush() in Spring Data?Medium
  • save() — persists/merges the entity. The SQL is not necessarily executed immediately; Hibernate may batch it and flush at transaction commit.
  • saveAndFlush() — persists and immediately flushes to the database within the current transaction, so the SQL runs right away.

Use saveAndFlush() when you need the database-generated ID or need subsequent native queries within the same transaction to see the changes immediately.

24
What is Optimistic vs Pessimistic Locking in JPA?Hard

Optimistic locking — assumes conflicts are rare. A @Version column is compared on update; if it changed since the entity was read, a OptimisticLockException is thrown. No database lock held.

@Entity
public class Product {
    @Version
    private Long version; // incremented on every update
}

Pessimistic locking — acquires a database row lock immediately, preventing other transactions from reading or writing. Higher contention, lower throughput:

@Lock(LockModeType.PESSIMISTIC_WRITE)
Optional<Product> findById(Long id);

Use optimistic locking for most cases. Use pessimistic only when conflicts are frequent and a retry is too expensive (e.g. financial deductions).

25
What is LazyInitializationException and how do you fix it?Medium

This exception occurs when you access a lazy-loaded association outside an active Hibernate session (transaction):

// Transaction closes after repository call
User user = userRepository.findById(id).get();
// Session is closed here
user.getOrders().size(); // LazyInitializationException!

Fixes:

  • Keep the transaction open (annotate the service method with @Transactional).
  • Use JOIN FETCH or @EntityGraph to eagerly load what you need.
  • Use a DTO/projection to fetch only the fields you need in one query.
  • Avoid spring.jpa.open-in-view=true (it hides the problem but causes performance issues).
26
What is the difference between CrudRepository, JpaRepository, and PagingAndSortingRepository?Easy
  • CrudRepository — basic CRUD: save, findById, findAll, delete.
  • PagingAndSortingRepository — extends CrudRepository, adds findAll(Pageable) and findAll(Sort).
  • JpaRepository — extends PagingAndSortingRepository, adds JPA-specific operations: flush, saveAndFlush, deleteInBatch, getById.

In most Spring Boot apps you extend JpaRepository — it gives you everything.

Spring Security
27
How does Spring Security work at a high level?Medium

Spring Security is a filter chain. Every HTTP request passes through a series of Filter implementations before reaching the servlet:

  1. Authentication Filter — extracts credentials (e.g. JWT from header, username/password from form).
  2. AuthenticationManager — delegates to AuthenticationProvider to validate credentials.
  3. SecurityContextHolder — on success, the authenticated user (Authentication object) is stored here for the duration of the request.
  4. AuthorizationFilterSecurityInterceptor checks whether the authenticated user has permission to access the requested resource.

You configure the filter chain by defining a SecurityFilterChain bean in Spring Boot 3+.

28
How do you implement JWT authentication in Spring Boot?Hard

The flow: client sends credentials → server returns JWT → client sends JWT in Authorization: Bearer header on subsequent requests → server validates the token.

// 1. Filter: extract and validate JWT on every request
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest req,
            HttpServletResponse res, FilterChain chain) {
        String header = req.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            String token = header.substring(7);
            if (jwtService.isValid(token)) {
                UsernamePasswordAuthenticationToken auth =
                    new UsernamePasswordAuthenticationToken(
                        jwtService.getUsername(token), null,
                        jwtService.getAuthorities(token));
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }
        chain.doFilter(req, res);
    }
}

// 2. Register the filter in SecurityFilterChain
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
        .csrf(csrf -> csrf.disable())
        .sessionManagement(s -> s.sessionCreationPolicy(STATELESS))
        .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/auth/**").permitAll()
            .anyRequest().authenticated())
        .build();
}
29
What is the difference between @PreAuthorize and @Secured?Medium
  • @Secured({"ROLE_ADMIN"}) — simple role-based restriction. Cannot use SpEL expressions.
  • @PreAuthorize("hasRole('ADMIN') and #id == authentication.principal.id") — supports full Spring Expression Language. Can access method arguments (#id), the authentication object, and call custom methods. Much more flexible.
  • @PostAuthorize — evaluates after the method returns; can filter based on the return value.

Enable method security with @EnableMethodSecurity on a @Configuration class.

30
What is CSRF and how does Spring Security handle it?Medium

CSRF (Cross-Site Request Forgery) is an attack where a malicious site tricks the user's browser into making authenticated requests to your API using the user's existing session cookie.

Spring Security enables CSRF protection by default for stateful (session-based) apps. It generates a CSRF token that must be included in mutating requests (POST, PUT, DELETE).

For stateless REST APIs using JWT: CSRF is not needed because there are no session cookies. Disable it explicitly:

http.csrf(csrf -> csrf.disable())
Only disable CSRF if you are using stateless JWT authentication. Keep it enabled for any app that uses session cookies.
31
What is OAuth2 and how does Spring Boot support it?Hard

OAuth2 is an authorisation framework that allows an application to access resources on behalf of a user without sharing credentials. Common roles: Resource Owner (user), Client (your app), Authorization Server (Google/Okta/Keycloak), Resource Server (your API).

Spring Boot supports OAuth2 via spring-boot-starter-oauth2-resource-server and spring-boot-starter-oauth2-client:

# Validate incoming JWTs from Keycloak
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://keycloak/realms/myrealm

# In SecurityFilterChain:
http.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))

The resource server validates the JWT signature and expiry automatically. You access claims via @AuthenticationPrincipal Jwt jwt.

32
How do you store passwords securely in Spring Boot?Medium

Always use BCryptPasswordEncoder (or Argon2PasswordEncoder for higher security). Never store plain text or MD5/SHA-1 hashed passwords.

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12); // work factor 12
}

// When registering a user:
user.setPassword(passwordEncoder.encode(rawPassword));

// When authenticating:
passwordEncoder.matches(rawPassword, storedHash); // returns true/false

BCrypt automatically includes a random salt, so the same password produces a different hash every time — making rainbow table attacks useless.

33
What is the UserDetailsService and how do you implement it?Medium

UserDetailsService is a single-method interface Spring Security calls to load a user by username during authentication:

@Service
public class CustomUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        return userRepository.findByEmail(username)
            .map(u -> User.builder()
                .username(u.getEmail())
                .password(u.getPassword())
                .roles(u.getRoles().toArray(String[]::new))
                .build())
            .orElseThrow(() -> new UsernameNotFoundException(username));
    }
}

Register it as a bean and Spring Security picks it up automatically.

34
What is method-level security and when would you use it over URL-level security?Hard

URL-level security in SecurityFilterChain is coarse-grained — it secures endpoints by pattern. Good for broad rules like "all /api/admin/** requires ADMIN role".

Method-level security with @PreAuthorize is fine-grained — it secures individual service methods using SpEL. Good when:

  • Access depends on the method arguments or the returned object (e.g. "user can only update their own profile").
  • The same endpoint is called with different permission requirements based on business logic.
  • You want security enforced regardless of how the method is called (not just via HTTP).

Best practice: use both. URL security as the outer guard, method security as fine-grained business rule enforcement.

Testing in Spring Boot
35
What is the difference between @SpringBootTest, @WebMvcTest, and @DataJpaTest?Medium
  • @SpringBootTest — loads the full application context. Slow but tests the whole stack end-to-end. Use for integration tests.
  • @WebMvcTest(UserController.class) — loads only the web layer (controllers, filters, security). Service dependencies must be mocked. Fast — good for controller unit tests.
  • @DataJpaTest — loads only JPA-related components (repositories, entity classes). Uses in-memory H2 by default. Rolls back after each test. Good for repository tests.
  • @MockBean — creates a Mockito mock and registers it as a Spring bean, replacing any existing bean of that type.
36
How do you write a unit test for a Spring Boot REST controller?Medium
@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void getUser_returnsUser_whenFound() throws Exception {
        given(userService.findById(1L))
            .willReturn(new UserDTO(1L, "Alice", "alice@example.com"));

        mockMvc.perform(get("/api/users/1")
                .contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.name").value("Alice"))
            .andExpect(jsonPath("$.email").value("alice@example.com"));
    }

    @Test
    void getUser_returns404_whenNotFound() throws Exception {
        given(userService.findById(99L))
            .willThrow(new ResourceNotFoundException("User not found"));

        mockMvc.perform(get("/api/users/99"))
            .andExpect(status().isNotFound());
    }
}
37
What is Testcontainers and why is it useful?Medium

Testcontainers is a Java library that spins up real Docker containers (PostgreSQL, Redis, Kafka etc.) during tests. This means your tests run against the actual database engine, not an in-memory substitute like H2 — catching compatibility issues early.

@SpringBootTest
@Testcontainers
class UserRepositoryTest {

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

    @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 UserRepository userRepository;

    @Test
    void savesUser() {
        User user = userRepository.save(new User("Alice"));
        assertThat(user.getId()).isNotNull();
    }
}

Spring Boot 3.1+ has built-in Testcontainers support via @ServiceConnection, reducing the boilerplate further.

38
What is the difference between @Mock and @MockBean?Medium
  • @Mock (Mockito) — creates a plain Mockito mock. No Spring context. Use in pure unit tests with @ExtendWith(MockitoExtension.class).
  • @MockBean (Spring Boot) — creates a Mockito mock and registers it as a Spring bean in the application context, replacing any existing bean of that type. Use in slice tests (@WebMvcTest, @SpringBootTest).
  • @InjectMocks (Mockito) — creates an instance of the class and injects @Mock fields into it. No Spring context needed.
39
What is @Transactional(rollbackFor) in tests?Medium

When you annotate a test method or class with @Transactional, Spring rolls back the database changes after each test automatically. This means each test starts with a clean state without needing explicit cleanup:

@DataJpaTest
@Transactional   // rolls back after each test method
class ProductRepositoryTest {
    @Autowired ProductRepository repo;

    @Test
    void findByCategory_returnsMatchingProducts() {
        repo.save(new Product("Widget", "TOOLS"));
        List<Product> found = repo.findByCategory("TOOLS");
        assertThat(found).hasSize(1);
    }   // changes rolled back here automatically
}

@DataJpaTest applies @Transactional by default. For @SpringBootTest you add it manually if you want auto-rollback.

40
How do you test Spring Security in a @WebMvcTest?Hard
@WebMvcTest(UserController.class)
class UserControllerSecurityTest {
    @Autowired MockMvc mockMvc;
    @MockBean UserService userService;
    @MockBean JwtAuthFilter jwtAuthFilter; // mock your custom filter

    @Test
    @WithMockUser(roles = "ADMIN")  // simulate an authenticated user
    void adminEndpoint_allowsAdmin() throws Exception {
        mockMvc.perform(get("/api/admin/users"))
            .andExpect(status().isOk());
    }

    @Test
    void adminEndpoint_blocks_unauthenticated() throws Exception {
        mockMvc.perform(get("/api/admin/users"))
            .andExpect(status().isUnauthorized());
    }
}

@WithMockUser populates the SecurityContext for the test. For JWT-based auth, use @WithMockUser or set up a custom SecurityMockMvcRequestPostProcessors.jwt().

41
What is the test pyramid and how does it apply to Spring Boot?Medium

The test pyramid recommends more fast, cheap tests at the bottom and fewer slow, expensive tests at the top:

  • Unit tests (base — most) — test a single class in isolation. @Mock, no Spring context. Milliseconds each.
  • Integration / slice tests (middle) — test a layer: @WebMvcTest for controllers, @DataJpaTest for repositories. Seconds each.
  • End-to-end tests (top — fewest)@SpringBootTest with a real database (Testcontainers). Full stack. Tens of seconds each.

Keep the pyramid shape: 70% unit, 20% integration, 10% E2E. Inverting it slows your build and makes tests brittle.

Microservices & Cloud
42
How do microservices communicate with each other in Spring Boot?Medium

Synchronous (HTTP/gRPC):

  • RestTemplate — older, blocking HTTP client. Still works but being superseded.
  • WebClient — non-blocking, reactive HTTP client. Preferred in Spring Boot 3.
  • @FeignClient (Spring Cloud OpenFeign) — declarative HTTP client. Define an interface and Spring generates the implementation.
@FeignClient(name = "inventory-service", url = "${inventory.url}")
public interface InventoryClient {
    @GetMapping("/inventory/{sku}")
    InventoryResponse checkStock(@PathVariable String sku);
}

Asynchronous (messaging):

  • Kafka — high-throughput event streaming.
  • RabbitMQ — traditional message broker for task queues.
  • AWS SQS / SNS — managed messaging on AWS.
43
What is a Circuit Breaker pattern and how do you implement it with Resilience4j?Hard

A circuit breaker monitors calls to a downstream service. When failures exceed a threshold, it "opens" the circuit and stops calling the service for a cool-down period — returning a fallback instead. This prevents cascading failures.

@Service
public class PaymentService {

    @CircuitBreaker(name = "paymentGateway", fallbackMethod = "paymentFallback")
    @Retry(name = "paymentGateway")
    @TimeLimiter(name = "paymentGateway")
    public CompletableFuture<PaymentResult> processPayment(PaymentRequest req) {
        return CompletableFuture.supplyAsync(() -> gatewayClient.pay(req));
    }

    public CompletableFuture<PaymentResult> paymentFallback(
            PaymentRequest req, Exception ex) {
        return CompletableFuture.completedFuture(
            PaymentResult.queued("Payment queued for retry"));
    }
}
# application.yml
resilience4j.circuitbreaker.instances.paymentGateway:
  failure-rate-threshold: 50
  wait-duration-in-open-state: 10s
  sliding-window-size: 10
44
What is service discovery and how does Spring Cloud Eureka work?Medium

In a microservices environment, instances start and stop dynamically — hardcoding IPs is impossible. Service discovery solves this.

Eureka is a Netflix service registry. Each service registers itself with the Eureka server on startup. Clients look up services by name and get a live instance address.

# Eureka Server
@SpringBootApplication
@EnableEurekaServer
public class DiscoveryServer { ... }

# Client (each microservice)
spring.application.name=order-service
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

In Kubernetes environments, Eureka is often replaced by Kubernetes Service DNS, which provides native service discovery without a separate registry.

45
What is an API Gateway and why is it needed in microservices?Medium

An API Gateway is a single entry point for all clients. It sits in front of all microservices and handles:

  • Routing — forward requests to the correct service.
  • Authentication — verify JWT or API keys once, before requests reach services.
  • Rate limiting — protect services from overload.
  • Load balancing — distribute traffic across instances.
  • SSL termination — handle HTTPS at the gateway, use HTTP internally.
  • Request/response transformation — add headers, strip fields.

Spring Cloud Gateway is the Spring-native choice (reactive, built on WebFlux). APISIX and Kong are popular open-source alternatives.

46
What is distributed tracing and how do you implement it in Spring Boot?Medium

When a single user request flows across multiple microservices, distributed tracing lets you follow that request end-to-end, measuring time spent in each service.

Spring Boot 3 uses Micrometer Tracing (replaces Spring Cloud Sleuth). Add the dependency and a tracing backend:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
    <groupId>io.zipkin.reporter2</groupId>
    <artifactId>zipkin-reporter-brave</artifactId>
</dependency>
management.tracing.sampling.probability=1.0
management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans

A trace ID is automatically propagated across HTTP calls and message headers. View the full trace in Zipkin or Jaeger.

47
How do you externalise configuration in a microservices environment?Medium

Three main approaches:

  • Spring Cloud Config Server — centralised server backed by a Git repo. Services pull config at startup. Supports encryption and dynamic refresh via /actuator/refresh.
  • Kubernetes ConfigMaps and Secrets — config injected as environment variables or mounted files. Kubernetes-native, no extra service needed.
  • AWS Parameter Store / Secrets Manager — managed config on AWS. Spring Cloud AWS integrates natively.

Secrets (passwords, API keys) should never be in property files or Git. Use Secrets Manager, Vault, or Kubernetes Secrets (ideally sealed with Sealed Secrets).

48
What is the Saga pattern for distributed transactions?Hard

In microservices, a single business operation (e.g. place order) may span multiple services (Order, Inventory, Payment). Traditional two-phase commit doesn't scale across service boundaries.

The Saga pattern breaks the transaction into a sequence of local transactions, each publishing an event. On failure, compensating transactions undo previous steps.

Two implementations:

  • Choreography — each service listens to events and reacts. No central coordinator. Simple but hard to track.
  • Orchestration — a Saga orchestrator (e.g. using AWS Step Functions or a custom service) tells each participant what to do in order. Easier to reason about, central visibility.

Example order flow: OrderCreated → Inventory.reserve → Payment.charge → OrderConfirmed. If payment fails: Payment.compensate → Inventory.release → OrderCancelled.

49
How do you dockerise a Spring Boot application?Medium

Option 1: Dockerfile (multi-stage build for small image):

FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY mvnw pom.xml ./
COPY src ./src
RUN ./mvnw package -DskipTests

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]

Option 2: Spring Boot Buildpacks (no Dockerfile needed):

./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=myapp:latest

Buildpacks produce a production-optimised, layered image automatically.

50
What is Spring Boot's support for Kafka?Medium

Add spring-kafka and configure the broker in application.yml:

spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=my-group
spring.kafka.consumer.auto-offset-reset=earliest
// Producer
@Service
public class OrderEventProducer {
    @Autowired KafkaTemplate<String, OrderEvent> kafka;

    public void send(OrderEvent event) {
        kafka.send("order-events", event.getOrderId(), event);
    }
}

// Consumer
@KafkaListener(topics = "order-events", groupId = "inventory-group")
public void handle(OrderEvent event) {
    inventoryService.reserve(event);
}
Actuator, Monitoring & Performance
51
What is Spring Boot Actuator and what endpoints does it provide?Easy

Actuator adds production-ready monitoring endpoints to your application. Key endpoints:

  • /actuator/health — application health status (UP/DOWN) including DB, cache, disk space.
  • /actuator/metrics — JVM, HTTP request, CPU metrics.
  • /actuator/info — custom app metadata (version, build info).
  • /actuator/env — all configuration properties (sensitive — restrict access).
  • /actuator/loggers — view and change log levels at runtime without restart.
  • /actuator/threaddump — thread dump for debugging deadlocks.
management.endpoints.web.exposure.include=health,metrics,info,loggers
management.endpoint.health.show-details=when-authorized
52
How do you create a custom health indicator?Medium
@Component
public class ExternalApiHealthIndicator implements HealthIndicator {

    private final ExternalApiClient client;

    @Override
    public Health health() {
        try {
            boolean ok = client.ping();
            if (ok) {
                return Health.up().withDetail("api", "reachable").build();
            }
            return Health.down().withDetail("api", "returned error").build();
        } catch (Exception e) {
            return Health.down(e).build();
        }
    }
}

Spring Boot registers this automatically and includes it in /actuator/health. The overall status is DOWN if any indicator is DOWN.

53
How does Spring Boot integrate with Prometheus and Grafana?Medium

Add the Micrometer Prometheus registry:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
management.endpoints.web.exposure.include=prometheus,health
management.metrics.export.prometheus.enabled=true

Prometheus scrapes /actuator/prometheus at regular intervals. Grafana connects to Prometheus as a data source and visualises the metrics. Spring Boot auto-exports JVM metrics, HTTP request duration, DB connection pool stats etc. without any extra code.

54
What is Spring Boot caching and how do you enable it?Medium

Enable caching with @EnableCaching, then annotate methods:

@Service
public class ProductService {

    @Cacheable(value = "products", key = "#id")
    public Product findById(Long id) {
        // only called when result is not in cache
        return productRepository.findById(id).orElseThrow();
    }

    @CacheEvict(value = "products", key = "#product.id")
    public Product update(Product product) {
        return productRepository.save(product);
    }

    @CachePut(value = "products", key = "#result.id")
    public Product create(Product product) {
        return productRepository.save(product);
    }
}

Default cache is ConcurrentHashMap (in-memory). For distributed caching add Redis:

spring.cache.type=redis
spring.data.redis.host=localhost
55
What is connection pooling and how does Spring Boot configure HikariCP?Medium

Connection pooling maintains a pool of pre-opened database connections. Reusing connections is far cheaper than opening a new TCP connection on every database call.

Spring Boot auto-configures HikariCP (the fastest Java connection pool) when spring-boot-starter-data-jpa is on the classpath.

spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000   # 30 seconds
spring.datasource.hikari.idle-timeout=600000        # 10 minutes
spring.datasource.hikari.max-lifetime=1800000       # 30 minutes

Monitor pool usage via /actuator/metrics/hikaricp.connections.active. If active connections stay at max-pool-size, you have a bottleneck.

56
How do you tune JVM settings for a Spring Boot application in production?Hard
java \
  -Xms512m -Xmx1g \                      # heap min/max
  -XX:+UseG1GC \                          # G1 GC (default Java 9+)
  -XX:MaxGCPauseMillis=200 \             # target GC pause
  -XX:+HeapDumpOnOutOfMemoryError \      # dump heap on OOM
  -XX:HeapDumpPath=/app/heapdump.hprof \
  -Dspring.profiles.active=prod \
  -jar app.jar

Key tips:

  • Set -Xms = -Xmx in containers to avoid heap resizing at runtime.
  • In Docker/K8s, add -XX:MaxRAMPercentage=75 instead of fixed heap — lets the JVM adapt to the container memory limit.
  • Enable GC logging to diagnose GC pauses: -Xlog:gc*:file=/app/gc.log
Advanced & Architecture
57
What is Spring WebFlux and when would you use it over Spring MVC?Hard

Spring MVC is servlet-based and blocking — each request occupies a thread for its entire duration. Under high load with many concurrent I/O-bound requests, threads pile up.

Spring WebFlux is reactive and non-blocking — built on Project Reactor and Netty. A small number of threads handle many concurrent requests because I/O never blocks a thread.

// WebFlux controller
@RestController
public class UserController {
    @GetMapping("/users/{id}")
    public Mono<User> getUser(@PathVariable Long id) {
        return userRepository.findById(id); // Mono = 0 or 1 item
    }

    @GetMapping("/users")
    public Flux<User> getAllUsers() {
        return userRepository.findAll(); // Flux = 0..N items
    }
}

Use WebFlux when: high concurrency with many slow I/O operations (external API calls, streaming), or you need server-sent events / WebSocket. Stick with MVC when: the team is unfamiliar with reactive programming, or the app is CPU-bound or uses blocking JDBC.

58
What is AOP in Spring and what is a real use case?Hard

Aspect-Oriented Programming separates cross-cutting concerns (logging, security, transactions, metrics) from business logic by intercepting method calls.

@Aspect
@Component
public class LoggingAspect {

    @Around("@annotation(com.example.Audited)")
    public Object logExecution(ProceedingJoinPoint pjp) throws Throwable {
        String method = pjp.getSignature().getName();
        log.info("START {}", method);
        long start = System.currentTimeMillis();
        try {
            Object result = pjp.proceed();
            log.info("END {} ({}ms)", method, System.currentTimeMillis()-start);
            return result;
        } catch (Exception e) {
            log.error("FAIL {} — {}", method, e.getMessage());
            throw e;
        }
    }
}

Real use cases: execution time logging, audit trails, retry logic, caching, rate limiting — all without cluttering business code. Spring uses AOP internally for @Transactional, @Cacheable and Spring Security's method-level annotations.

59
What is GraalVM Native Image and Spring Boot's AOT support?Hard

GraalVM Native Image compiles a Spring Boot application ahead-of-time into a native executable — no JVM required at runtime. The result:

  • Startup time: milliseconds instead of seconds.
  • Memory footprint: significantly reduced.
  • No JVM warm-up period.

Spring Boot 3 has built-in AOT (Ahead-of-Time) processing support. Spring analyses the application at build time and generates optimised code for GraalVM:

# Build native image with Maven
./mvnw -Pnative native:compile

# Or with Buildpacks
./mvnw spring-boot:build-image -Pnative

Trade-offs: longer build times (minutes), dynamic features (reflection, proxies) need explicit hints, and debugging is harder. Ideal for serverless functions and Kubernetes workloads where fast startup and low memory matter.

60
How would you design a Spring Boot application for high availability in production?Hard

A checklist for a production-ready, highly available Spring Boot service:

  • Multiple instances — run at least 3 instances behind a load balancer. Use Kubernetes Deployment with replicas: 3.
  • Health checks — Kubernetes liveness (/actuator/health/liveness) and readiness (/actuator/health/readiness) probes.
  • Graceful shutdownserver.shutdown=graceful + spring.lifecycle.timeout-per-shutdown-phase=30s. Drains in-flight requests before stopping.
  • Stateless sessions — store session in Redis, not in the JVM heap.
  • Circuit breakers — Resilience4j around all downstream calls.
  • Database connection pool sizing — size pool per instance to not exceed DB max connections (pool_size × instances ≤ db_max_connections).
  • PodDisruptionBudget — ensure at least N-1 pods are running during rolling updates.
  • Observability — structured JSON logging, Micrometer metrics to Prometheus, distributed tracing to Jaeger.
  • Secrets management — no credentials in environment variables in plain text; use Kubernetes Secrets or Vault.

What to Study Next

If you have these 60 questions solid, you are well-prepared for most Spring Boot interviews at junior through senior level. For senior/lead roles, go deeper on: