Spring Boot Interview Questions for Senior Developers
1. How does Spring Boot’s auto-configuration work internally?
Business Requirement: “As a developer, I want to quickly set up a new web service with a database connection without manually configuring every single bean, so I can start writing business logic faster.”
Answer: Spring Boot’s auto-configuration is triggered by the @EnableAutoConfiguration annotation (which is part of @SpringBootApplication). It works by scanning the classpath for specific JARs.
- Spring Boot checks a file named
spring.factories(ororg.springframework.boot.autoconfigure.AutoConfiguration.importsin newer versions) inside thespring-boot-autoconfigure.jar. - This file contains a list of
AutoConfigurationclasses. - Each configuration class is evaluated based on conditions defined by
@ConditionalOn...annotations (e.g.,@ConditionalOnClass,@ConditionalOnBean,@ConditionalOnProperty). - If the conditions are met, the beans defined in that configuration class are created and added to the application context. For example, if
spring-boot-starter-data-jpais on the classpath,DataSourceAutoConfigurationandJpaRepositoriesAutoConfigurationwill be activated.
2. What is the purpose of Spring Boot Starters?
Business Requirement: “As a developer, I need to add web and JPA capabilities to my project. I want to avoid version conflicts between libraries and ensure all necessary dependencies are included with a single configuration entry.”
Answer: Spring Boot Starters are pre-packaged dependency descriptors that simplify dependency management. Instead of manually adding a list of compatible libraries, you include a single starter POM. For example, including spring-boot-starter-web brings in Spring MVC, Tomcat (as an embedded server), and Jackson for JSON serialization, all with compatible versions. This reduces configuration errors and boilerplate.
3. What is Spring Boot Actuator and what are its most useful endpoints?
Business Requirement: “As a DevOps engineer, I need to monitor the health of our running application in production, check its memory usage, and be able to change log levels for debugging without restarting the service.”
Answer: Spring Boot Actuator provides production-ready features for monitoring and managing a running application. It exposes several endpoints over HTTP or JMX. The most useful endpoints are:
/actuator/health: Shows the application’s health status, aggregating the status of various components like the database and disk space./actuator/metrics: Provides detailed application metrics, such as JVM memory usage, CPU usage, and HTTP request statistics./actuator/info: Displays arbitrary application info./actuator/loggers: Allows viewing and modifying application log levels at runtime, which is extremely useful for debugging production issues without a restart.
4. How does Spring Boot handle external configurations and property precedence?
Business Requirement: “As a developer, I need our application to use a different database URL in production than in development. I want to override the default configuration using environment variables or command-line arguments without changing the code.”
Answer: Spring Boot uses a specific order of precedence to load external configurations, allowing you to override default values. The order is (from lowest to highest precedence):
- Default properties (specified in the code).
@PropertySourceannotations on@Configurationclasses.- Properties in
application.propertiesorapplication.ymlinside the packaged JAR. - Properties in
application.propertiesorapplication.ymloutside the packaged JAR (in the same directory). - OS environment variables.
- Command-line arguments (e.g.,
--server.port=9090).
This hierarchy makes it very flexible to configure an application for different environments (dev, staging, prod).
5. How would you handle transactions in a Spring Boot application?
Business Requirement: “When a user transfers money, we must ensure that the amount is debited from one account and credited to another as a single, atomic operation. If any part of the process fails, the entire transaction must be rolled back.”
Answer: Spring Boot simplifies transaction management with the @Transactional annotation.
- Local Transactions: For single-database operations, applying
@Transactionalto a service method is sufficient. Spring will start a transaction before the method executes and commit it upon successful completion or roll it back if an unchecked exception is thrown. - Distributed Transactions: For operations spanning multiple services or databases, a simple
@Transactionalis not enough. I would use a pattern like Saga to ensure eventual consistency. This involves a sequence of local transactions, with compensating transactions to undo work if a step fails.
6. What is the difference between @Component, @Service, @Repository, and @Controller?
Answer: While all these annotations mark a class as a Spring bean for dependency injection, they provide semantic meaning and some extra functionality: Business Requirement: “As a lead developer, I want our team to structure the application into clear layers (presentation, business logic, data access) to improve maintainability. We need a way to clearly mark classes based on their role.”
@Component: A generic stereotype for any Spring-managed component.@Service: Indicates the class holds business logic (service layer).@Repository: Used for the persistence layer. It enables Spring’s exception translation feature, which converts technology-specific exceptions (likeSQLException) into Spring’s unifiedDataAccessExceptionhierarchy.@Controller/@RestController: Used for the presentation layer (e.g., Spring MVC).@RestControlleris a convenience annotation that combines@Controllerand@ResponseBody.
7. How do you handle exceptions in a Spring Boot REST API?
Business Requirement: “When a user requests a product that doesn’t exist, our API should return a consistent JSON error message with a 404 Not Found status code, instead of an unhandled stack trace.”
Answer: The best practice is to use a centralized exception handler with @RestControllerAdvice.
- Create a class annotated with
@RestControllerAdvice. - Within this class, create methods annotated with
@ExceptionHandlerfor each specific exception you want to handle (e.g.,ResourceNotFoundException). - These methods can return a
ResponseEntitywith a custom error object and an appropriate HTTP status code (e.g., 404 Not Found). This keeps the controller logic clean and provides consistent error responses across the API.
8. What is your strategy for testing a Spring Boot application?
Business Requirement: “As a QA lead, I need to ensure that new code changes don’t break existing functionality. We need a comprehensive testing strategy that covers individual components, the integration between them, and the API endpoints.”
Answer: I use a multi-layered testing strategy:
- Unit Tests: Using JUnit and Mockito to test individual classes (like services or utility classes) in isolation. I mock all external dependencies.
- Integration Tests: I use
@SpringBootTestto load the full application context and test the interaction between different layers (e.g., controller -> service -> repository). For the database, I often use an in-memory database like H2 or Testcontainers to ensure tests are isolated and repeatable. - Slice Tests: For testing specific layers, I use annotations like
@WebMvcTest(for controllers) or@DataJpaTest(for repositories). These load only a slice of the application context, making tests faster than a full@SpringBootTest.
9. How does Spring Boot support asynchronous processing?
Business Requirement: “After a user registers, we need to send them a welcome email. This email-sending process should not block the API response, so the user gets an immediate confirmation of their registration.”
Answer: Spring Boot supports asynchronous processing via the @Async annotation.
- Enable it by adding
@EnableAsyncto a configuration class. - Annotate any public method with
@Async. When this method is called, Spring will execute it in a separate thread from a thread pool. - The method can return a
CompletableFutureto allow the caller to get the result of the asynchronous computation later. This is crucial for building non-blocking, responsive applications.
10. How would you secure a REST API with Spring Boot?
Business Requirement: “Our API exposes sensitive user data. We need to ensure that only authenticated users can access their own data and that unauthorized users are blocked.”
Answer: I would use Spring Security. For a modern REST API, a token-based approach is standard.
- Include the
spring-boot-starter-securitydependency. - Configure a
SecurityFilterChainbean to define security rules. I would disable CSRF and configure stateless session management (SessionCreationPolicy.STATELESS). - I’d implement a JWT (JSON Web Token) based authentication filter. The client would authenticate via a login endpoint (e.g.,
/api/login) to get a JWT. - For subsequent requests, the client sends the JWT in the
Authorization: Bearer <token>header. The custom filter validates the token and sets the authenticated user in theSecurityContext. - Method-level security can be applied using annotations like
@PreAuthorizeto control access based on user roles.
11. What is the difference between singleton and prototype bean scopes?
Business Requirement: “In our e-commerce application, every user needs their own unique shopping cart object to store items. We must ensure that one user’s cart is not shared with another user during the same session.”
Answer:
- Singleton (Default): Only one instance of the bean is created per Spring container. Every time the bean is requested, the same instance is returned. This is suitable for stateless beans like services and repositories.
- Prototype: A new instance of the bean is created every time it is requested. This is useful for stateful beans where you need a unique object for each use case, for example, a shopping cart object for each user session.
12. How does Spring Boot support database migrations?
Business Requirement: “As our application evolves, we need to add new columns to our database tables. This schema change must be applied automatically and consistently across all developer machines and in our production environment during deployment.” Answer: Spring Boot has excellent auto-configuration support for database migration tools like Flyway and Liquibase.
- Add the dependency for either Flyway or Liquibase to your
pom.xml. - Create SQL (for Flyway) or XML/YAML (for Liquibase) migration scripts in the default location (
src/main/resources/db/migration). - When the application starts, Spring Boot will automatically detect the migration tool and run any new migration scripts to update the database schema before the application becomes available. This ensures the database schema is always in sync with the application code.
13. How do you implement the Circuit Breaker pattern in Spring Boot?
Business Requirement: “Our Order Service calls an external Payment Service. If the Payment Service is down, we don’t want our Order Service to become unresponsive. Instead, it should fail fast and return a ‘Payment service unavailable’ message to the user immediately.” Answer: The Circuit Breaker pattern is essential for building resilient microservices to prevent cascading failures. In Spring Boot, this is typically implemented using Spring Cloud Circuit Breaker with Resilience4j.
- Dependency: First, I’d add the
spring-cloud-starter-circuitbreaker-resilience4jdependency to thepom.xml. - Implementation: I would annotate a method that calls a potentially failing external service with
@CircuitBreaker. - Fallback: The most important part is defining a
fallbackMethod. This method is executed if the external service call fails or if the circuit is “open” (meaning it has detected too many recent failures). The fallback method should have the same signature and return a default response (e.g., from a cache or a generic message).
This pattern stops the application from repeatedly calling a service that is down, allowing it to recover and preventing the local application from exhausting its resources. The circuit breaker will periodically try the call again (the “half-open” state) to see if the downstream service has recovered.
14. How do you use Spring Profiles to manage environment-specific configurations?
Business Requirement: “Our application needs to connect to a different database for development, testing, and production. We need a clean way to manage these different configurations without changing the code for each environment.”
Answer: Spring Profiles are the standard way to segregate parts of your application configuration and make them available only in certain environments.
- Profile-specific Properties: I would create separate property files for each environment, such as
application-dev.properties(for development) andapplication-prod.properties(for production). Each file would contain environment-specific values, like the database URL. - Conditional Bean Registration: For beans that should only be active in a specific environment (e.g., a mock service for local testing), I would use the
@Profile("dev")annotation. This bean will only be created when the ‘dev’ profile is active. - Activating a Profile: The active profile can be set in the main
application.propertiesfile usingspring.profiles.active=devor, more commonly, as a command-line argument when running the application:java -jar myapp.jar --spring.profiles.active=prod. This makes it easy to switch configurations without rebuilding the project.
15. How do you improve performance with Spring’s caching support?
Business Requirement: “Our application has a method that fetches a list of product categories from the database. This data rarely changes, but the method is called frequently, causing unnecessary database load. We need to cache this data to improve response times.”
Answer: Spring Boot provides a powerful caching abstraction that can be easily enabled.
- Enable Caching: First, I would add
@EnableCachingto a main configuration class. - Annotate the Method: Then, I would annotate the expensive method (e.g.,
getProductCategories()) with@Cacheable. For example:@Cacheable("categories").
When this method is called for the first time, it will execute, and its result will be stored in a cache named “categories”. On all subsequent calls, the result will be returned directly from the cache without executing the method again. This dramatically reduces database hits and improves application performance. For cache invalidation, I would use other annotations like @CacheEvict when the underlying data changes.
Comments