🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.
▶️ Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube
▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube
In this guide, we will discuss the 60+ most frequently asked real-time Spring Boot and Microservices interview questions and answers for both beginners and experienced developers.
Modern Spring Boot interviews focus on real-world architecture and production thinking. These questions test how systems are designed, monitored, optimized, and secured under real load conditions.
1) How would you handle inter-service communication in a microservice architecture using Spring Boot?
In a microservice architecture, communication generally happens in two ways: synchronous and asynchronous.
For synchronous communication, HTTP-based REST calls are common. In modern Spring Boot applications, WebClient is preferred over RestTemplate because it supports non-blocking communication and integrates well with reactive systems. However, production-grade communication requires more than just an HTTP call. It must include timeouts, retries, circuit breakers, and proper error handling to prevent cascading failures. Without these safeguards, a slow downstream service can degrade the entire system.
For asynchronous communication, message brokers such as Kafka or RabbitMQ are commonly used. This approach improves decoupling and resilience. Instead of directly calling another service, events are published and consumed independently. This pattern is especially effective for workflows like order processing or notification systems.
Example using WebClient with timeout:
@Service
public class InventoryClient {
private final WebClient webClient;
public InventoryClient(WebClient.Builder builder) {
this.webClient = builder.baseUrl("http://inventory-service").build();
}
public Mono<Boolean> isInStock(String sku) {
return webClient.get()
.uri("/api/v1/inventory/{sku}", sku)
.retrieve()
.bodyToMono(Boolean.class)
.timeout(Duration.ofSeconds(2));
}
}
2) Can you explain the caching mechanism available in Spring Boot?
Spring Boot provides caching through the Spring Cache abstraction. This abstraction separates caching logic from business logic. Instead of directly interacting with a specific caching provider, developers annotate methods, and Spring handles cache management internally.
When a method is annotated with @Cacheable, Spring uses AOP proxies to intercept the call. It checks whether a cached value exists for the given key. If it does, the method execution is skipped and the cached value is returned. If not, the method executes and the result is stored in the cache. This approach keeps the service layer clean and maintainable.
Spring Boot supports multiple providers such as Caffeine, Redis, Ehcache, and Hazelcast. The choice depends on whether the system is single-instance or distributed.
3) How would you implement caching in a Spring Boot application?
Caching implementation starts with enabling caching globally using @EnableCaching. After that, a cache provider must be configured. For single-instance applications, in-memory caching such as Caffeine is sufficient. For distributed systems running multiple instances, Redis is typically preferred.
Below is an example using Caffeine as a cache provider.
Enable caching:
@SpringBootApplication
@EnableCaching
public class DemoApplication {}
Configure Caffeine:
@Configuration
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("products");
cacheManager.setCaffeine(
Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(Duration.ofMinutes(10))
);
return cacheManager;
}
}
Use caching in service layer:
@Service
public class ProductService {
@Cacheable(cacheNames = "products", key = "#id")
public Product getProductById(Long id) {
simulateSlowCall();
return new Product(id, "Sample Product");
}
@CacheEvict(cacheNames = "products", key = "#id")
public void updateProduct(Long id) {
// update logic
}
private void simulateSlowCall() {
try { Thread.sleep(3000); } catch (Exception ignored) {}
}
}
4) Your Spring Boot application is experiencing performance issues under high load. What steps would you take?
The first step is identifying the bottleneck rather than immediately applying fixes. Performance issues typically originate from one of the following areas:
- Database (slow queries, missing indexes, N+1 queries)
- Thread pool exhaustion
- Connection pool misconfiguration
- Memory pressure or frequent garbage collection
- External service latency
- Blocking I/O operations
Monitoring tools such as Spring Boot Actuator, Micrometer, Prometheus, and application logs help identify latency patterns and resource usage. Load testing tools can reproduce the issue under controlled conditions.
After identifying the root cause, optimization strategies may include:
- Adding caching
- Optimizing database queries and adding indexes
- Tuning HikariCP connection pool
- Adjusting thread pool configuration
- Introducing asynchronous processing
- Scaling horizontally behind a load balancer
- JVM tuning for heap and GC behavior
Performance tuning must always be based on measurable metrics rather than assumptions.
5) What are the best practices for versioning REST APIs in a Spring Boot application?
API versioning ensures backward compatibility when evolving systems. The most common approach is URI versioning, such as /api/v1/users. This method is simple, visible, and easy to manage in routing systems.
Other strategies include header-based versioning and media-type versioning. Header-based versioning keeps URLs clean but may complicate client configuration. Media-type versioning provides fine-grained control but increases complexity.
Example using URI versioning:
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 {
@GetMapping("/{id}")
public String getUser(@PathVariable Long id) {
return "User V1";
}
}
Versioning strategy should be consistent across the entire system to avoid confusion.
6) How does Spring Boot simplify the data access layer implementation?
Spring Boot simplifies data access through Spring Data JPA. Instead of writing boilerplate DAO implementations, developers define repository interfaces, and Spring generates implementations at runtime.
Spring Boot automatically configures:
- DataSource
- JPA provider (Hibernate)
- Transaction manager
- Connection pooling (HikariCP by default)
Example repository:
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
This approach reduces repetitive code and enforces a consistent data access pattern.
7) What are conditional annotations, and what is their purpose in Spring Boot?
Conditional annotations control whether a bean should be created based on specific conditions. They are fundamental to Spring Boot’s auto-configuration system.
Examples include:
@ConditionalOnClass@ConditionalOnProperty@ConditionalOnMissingBean
These annotations allow Spring Boot to configure components automatically only when required dependencies or properties are present.
Example:
@Bean
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
public FeatureService featureService() {
return new FeatureService();
}
This ensures that the bean loads only when the property is enabled.
8) Explain the role of @EnableAutoConfiguration and how Spring Boot achieves auto-configuration internally.
@EnableAutoConfiguration allows Spring Boot to automatically configure beans based on the classpath and application properties. It eliminates the need for manual configuration.
Internally, Spring Boot scans auto-configuration classes listed in its metadata files. Each auto-configuration class uses conditional annotations to determine whether it should apply. If the required classes and properties are present, Spring creates the necessary beans.
Most applications rely on @SpringBootApplication, which already includes @EnableAutoConfiguration.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
9) What are Spring Boot Actuator endpoints?
Spring Boot Actuator provides production-ready monitoring and management endpoints. These endpoints expose application health, metrics, configuration, and runtime information.
Common endpoints include:
/actuator/health/actuator/metrics/actuator/info/actuator/threaddump
These endpoints integrate with monitoring systems such as Prometheus and Grafana to track application behavior in real time.
10) How can we secure the Actuator endpoints?
Actuator endpoints should never be fully exposed in production environments. Security can be applied by limiting exposure and integrating with Spring Security.
First, restrict which endpoints are exposed:
management.endpoints.web.exposure.include=health,info
Then apply security configuration:
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
.requestMatchers("/actuator/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.build();
}
}
Sensitive endpoints such as metrics or environment variables should require authentication and appropriate roles.
11) What strategies would you use to optimize the performance of a Spring Boot application?
Performance optimization always starts with measurement. Without metrics, tuning becomes guesswork. The first step is enabling Actuator and collecting metrics such as response time percentiles, thread pool utilization, database pool usage, and memory behavior. Load testing should reproduce the issue consistently before applying changes.
Once the bottleneck is identified, optimization depends on where the issue lies:
If the database is slow, optimize queries, add indexes, fix N+1 issues in JPA, and introduce caching for read-heavy endpoints. If threads are blocked, adjust the server thread pool and ensure no long-running blocking operations occur on request threads. If memory usage is high, analyze heap dumps and garbage collection behavior. If external services are slow, introduce timeouts, retries, circuit breakers, and possibly asynchronous processing.
Other common improvements include:
- Enabling HTTP compression
- Using pagination instead of returning large datasets
- Configuring connection pooling properly (HikariCP tuning)
- Offloading heavy work to background jobs
- Scaling horizontally behind a load balancer
Performance improvements must always be validated with before-and-after metrics.
12) How can we handle multiple beans of the same type?
When multiple beans of the same type exist, Spring cannot decide which one to inject automatically. This results in a NoUniqueBeanDefinitionException.
There are three common ways to resolve this:
1. @Primary Marks one bean as the default choice.
@Service
@Primary
class EmailNotificationService implements NotificationService {}
2. @Qualifier Specifies exactly which bean should be injected.
@Service("smsService")
class SmsNotificationService implements NotificationService {}
@Autowired
@Qualifier("smsService")
private NotificationService notificationService;
3. Inject all implementations Sometimes all beans are needed.
@Autowired
private List<NotificationService> services;
The correct approach depends on whether a default implementation exists or multiple implementations are needed dynamically.
13) What are some best practices for managing transactions in Spring Boot application?
Transaction management should always be handled at the service layer, not the controller layer. The business logic defines transaction boundaries.
The @Transactional annotation ensures atomicity. If an unchecked exception occurs, the transaction rolls back automatically. However, it is important to remember that transaction proxies only work when methods are called from outside the bean, not internally.
Best practices include:
- Keep transactions short.
- Avoid calling remote services inside transactions.
- Avoid long-running operations within a transaction.
- Use appropriate isolation levels when required.
- Clearly define rollback rules when using checked exceptions.
Example:
@Service
public class OrderService {
@Transactional
public void placeOrder(Order order) {
saveOrder(order);
updateInventory(order);
}
}
Poor transaction management can lead to deadlocks, connection exhaustion, and data inconsistency.
14) How do you approach testing in Spring Boot application?
Testing strategy should be layered.
Unit tests focus on business logic using Mockito.
Slice tests test specific layers such as @WebMvcTest for controllers or @DataJpaTest for repositories.
Integration tests use @SpringBootTest to load the full application context.
For database testing, Testcontainers is often preferred to simulate real database environments.
Testing should verify behavior, not implementation details. Mocking external services is common, but over-mocking can reduce test reliability. Integration tests provide higher confidence but are slower.
15) Discuss the use of Spring Boot Test and @MockBean annotations?
@SpringBootTest loads the entire Spring application context. It is useful for integration tests where full wiring is required.
@MockBean replaces a real bean in the application context with a Mockito mock. This allows isolation of specific components during testing without modifying configuration.
Example:
@SpringBootTest
class OrderServiceTest {
@MockBean
private PaymentService paymentService;
@Autowired
private OrderService orderService;
@Test
void testOrderPlacement() {
Mockito.when(paymentService.processPayment(Mockito.any()))
.thenReturn(true);
orderService.placeOrder(new Order());
}
}
This approach maintains real Spring wiring while controlling specific dependencies.
16) What advantages does YAML offer over properties file in Spring Boot? Are there limitations?
YAML supports hierarchical configuration naturally, making complex configurations easier to read and manage. It reduces duplication and improves readability in large configuration files.
Example YAML:
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/app
username: root
password: root
Compared to properties:
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/app
spring.datasource.username=root
spring.datasource.password=root
However, YAML is indentation-sensitive. A single spacing error can break configuration. Additionally, properties files are sometimes easier for simple flat configurations. YAML may not be ideal when environment variable overrides are heavily used.
17) Explain how Spring Boot profile works?
Profiles allow different configurations for different environments such as development, testing, and production.
Configuration files can be separated:
application-dev.yml
application-prod.yml
To activate a profile:
spring.profiles.active=dev
Spring loads application.yml first, then overrides properties with the active profile configuration. Profiles help avoid hardcoding environment-specific settings inside code.
18) What is Aspect-Oriented Programming in the Spring Framework?
Aspect-Oriented Programming (AOP) allows separation of cross-cutting concerns such as logging, security, auditing, and transaction management from business logic.
Instead of duplicating logging code in multiple methods, an aspect intercepts method calls and applies logic transparently.
Example:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("Method execution started");
}
}
AOP improves modularity and keeps business code clean.
19) What is Spring Clou,d and how is it useful for building microservices?
Spring Cloud provides tools for distributed system challenges such as:
- Service discovery
- Configuration management
- Circuit breakers
- Distributed tracing
- API gateway
- Load balancing
In microservices, these concerns become complex quickly. Spring Cloud integrates solutions like Eureka, Config Server, Gateway, and Resilience4j to simplify distributed architecture.
Without such tools, microservices become difficult to manage at scale.
20) How does Spring Boot make the decision on which server to use?
Spring Boot auto-configures an embedded server based on the dependencies available on the classpath.
If spring-boot-starter-web is included, Tomcat is used by default.
If Jetty or Undertow dependency is present instead, Boot configures those servers.
The decision is purely dependency-driven. Boot checks the classpath and applies the matching auto-configuration.
Example for Jetty:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Spring Boot’s auto-configuration detects this and replaces Tomcat automatically.
21) How to get the list of all the beans in a Spring Boot application?
Spring Boot runs on the Spring ApplicationContext, which contains all registered beans. The clean way to list beans is to inject the ApplicationContext (or ListableBeanFactory) and print getBeanDefinitionNames().
This is useful in debugging when something unexpected gets auto-configured, when multiple beans exist for the same type, or when a bean is missing due to conditional configuration. In production, printing all beans is not recommended in logs, but it is very useful locally or in controlled troubleshooting.
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class BeanLister implements CommandLineRunner {
private final ApplicationContext context;
public BeanLister(ApplicationContext context) {
this.context = context;
}
@Override
public void run(String... args) {
String[] beans = context.getBeanDefinitionNames();
Arrays.sort(beans);
System.out.println("Total beans: " + beans.length);
for (String bean : beans) {
System.out.println(bean);
}
}
}
For a safer production approach, Actuator’s /actuator/beans endpoint can show beans, but it must be secured and not exposed publicly.
22) Describe a Spring Boot project where performance was significantly improved. What techniques were used?
A strong interview answer should describe a realistic bottleneck and explain how it was measured and fixed. Most Spring Boot performance issues come from database inefficiency, thread blocking, external service latency, or excessive object allocation leading to GC pressure.
A typical real improvement looks like this: the system was slow under load, metrics showed high p95 latency, and database monitoring showed slow queries and N+1 problems. Fixes included query optimization, adding missing indexes, converting eager relationships to lazy where appropriate, introducing pagination, and caching read-heavy endpoints (Caffeine/Redis). After that, load testing validated improvement and Actuator metrics confirmed lower latency and reduced DB load.
Example of caching a read-heavy endpoint:
@EnableCaching
@SpringBootApplication
class App {}
@Service
class ProductService {
@Cacheable(cacheNames = "products", key = "#id")
public Product getProduct(Long id) {
// DB hit here
return new Product(id, "P-" + id);
}
}
23) Explain Spring Boot’s embedded Servlet containers
Spring Boot packages an embedded web server inside the application, so the application runs as a self-contained process. Instead of building a WAR and deploying it to an external Tomcat, Boot typically builds a runnable JAR that includes Tomcat (default), Jetty, or Undertow.
This simplifies deployment significantly. The same artifact can run locally, in a container, or on a server without installing and managing an external application server. It also improves portability because the server version is controlled through dependencies rather than environment setup.
A standard Spring Boot app runs like this:
java -jar app.jar
To switch from Tomcat to Jetty, Tomcat starter is excluded and Jetty starter is added.
24) How does Spring Boot make DI easier compared to traditional Spring?
Traditional Spring often requires more manual configuration, explicit XML, or Java config for many infrastructure beans. Spring Boot reduces this by using auto-configuration and starter dependencies that bring sensible defaults.
Spring Boot also encourages constructor injection, and it auto-configures common components like DataSource, transaction manager, ObjectMapper, and embedded server. As a result, dependency injection becomes mostly about wiring business components, while Boot handles infrastructure wiring automatically based on what’s on the classpath and what properties are set.
Example of clean DI:
@Service
class OrderService {
private final OrderRepository repo;
public OrderService(OrderRepository repo) {
this.repo = repo;
}
}
No XML, no manual bean registration needed.
25) How does Spring Boot simplify managing application secrets across environments?
Secrets should never be hard-coded or committed to Git. Spring Boot supports externalized configuration, so secrets can be injected at runtime using environment variables, secret managers, or encrypted config systems.
Common production approaches:
- Environment variables (
DB_PASSWORD,JWT_SECRET) - Docker/Kubernetes secrets mounted as env vars or files
- Secret managers (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, HashiCorp Vault)
- Spring Cloud Config (often combined with encryption)
The best approach depends on deployment environment, but the key idea is always the same: store secrets outside code and inject them securely.
Example using environment variables:
spring.datasource.password=${DB_PASSWORD}
In Kubernetes, DB_PASSWORD comes from a secret, not the repository.
26) Explain Spring Boot’s approach to handle asynchronous operations
Asynchronous execution in Spring Boot is commonly handled using @Async, CompletableFuture, and task executors. This allows heavy or slow tasks to run in a separate thread pool instead of blocking request threads.
The right approach depends on the workload. For CPU-heavy tasks, a dedicated executor prevents starvation of request threads. For I/O-heavy tasks, non-blocking approaches (WebFlux) or messaging systems often work better. Also, async tasks should include timeouts, error handling, and proper executor sizing to avoid uncontrolled thread creation.
Example:
@EnableAsync
@Configuration
class AsyncConfig {
@Bean
public Executor taskExecutor() {
return java.util.concurrent.Executors.newFixedThreadPool(10);
}
}
@Service
class ReportService {
@Async
public CompletableFuture<String> generateReport() {
// heavy work
return CompletableFuture.completedFuture("DONE");
}
}
27) How would you secure sensitive data accessed by users with different roles?
Role-based security starts with authentication (who the user is) and authorization (what the user can access). Sensitive data must be protected at the API layer and, when required, at the data layer too.
Typical production strategy:
- Spring Security with JWT/OAuth2
- Role-based access control for endpoints (ADMIN, MANAGER, USER)
- Method-level security for sensitive business operations (
@PreAuthorize) - Data-level filtering when users should only see their own records
- Encrypt sensitive fields at rest and enforce TLS in transit
Example with role-based endpoint protection:
@EnableMethodSecurity
@Configuration
class SecurityConfig {}
@Service
class PayrollService {
@PreAuthorize("hasRole('ADMIN')")
public String getAllSalaries() {
return "Sensitive payroll data";
}
@PreAuthorize("hasRole('USER') and #userId == authentication.name")
public String getMyData(String userId) {
return "My sensitive data";
}
}
28) File upload endpoint: how to handle uploads and where to store files?
File uploads should be validated and stored safely. The controller should accept multipart files, validate size and type, scan if needed, and store using a safe naming strategy. Storing files on local disk can work for single-instance systems, but in scalable systems with multiple instances, files should be stored in external storage such as S3, Google Cloud Storage, Azure Blob, or a shared network store.
Best practice approach:
- Validate file size and type
- Store outside the application jar
- Use unique file names (UUID)
- Store metadata in DB (original name, content type, size, storage path)
- Use virus scanning for untrusted uploads
- Secure download access with authorization
Example:
@RestController
@RequestMapping("/api/v1/files")
class FileController {
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) throws Exception {
if (file.isEmpty()) throw new IllegalArgumentException("Empty file");
if (file.getSize() > 10 * 1024 * 1024) throw new IllegalArgumentException("Too large");
String filename = java.util.UUID.randomUUID() + "_" + file.getOriginalFilename();
Path target = Path.of("uploads").resolve(filename);
Files.createDirectories(target.getParent());
Files.write(target, file.getBytes());
return "Uploaded as: " + filename;
}
}
For production, object storage is usually the correct answer.
29) Difference between authentication and authorization in Spring Security
Authentication verifies identity. It answers: “Who are you?” Authorization checks permissions. It answers: “What are you allowed to do?”
A user can be authenticated but not authorized to access a particular endpoint. For example, a logged-in user without ADMIN role should not access /admin/*.
In Spring Security, authentication is handled by filters and authentication providers. Authorization is enforced by request matchers or method-level security annotations.
30) After successful registration, how to send a welcome email?
Sending an email should not block the registration request. The registration endpoint should complete quickly, then the email should be sent asynchronously.
Common production approaches:
- Use
@Asyncfor simple systems - Use messaging (Kafka/RabbitMQ) for reliable email workflows
- Use retries and dead-letter queues for failures
- Use a transactional outbox pattern if email must not be lost
Simple @Async approach:
@Service
class EmailService {
private final JavaMailSender mailSender;
EmailService(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
@Async
public void sendWelcomeEmail(String to) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject("Welcome!");
message.setText("Thanks for registering.");
mailSender.send(message);
}
}
Registration flow:
@Service
class RegistrationService {
private final EmailService emailService;
RegistrationService(EmailService emailService) {
this.emailService = emailService;
}
public void register(String email) {
// save user
emailService.sendWelcomeEmail(email);
}
}
For high reliability, messaging-based email is a stronger answer.
31) What is Spring Boot CLI, and how to execute a Spring Boot project using Boot CLI?
Spring Boot CLI is a command-line tool that makes it fast to prototype Spring applications, especially using Groovy scripts. It can run apps without creating a full Maven/Gradle project and can automatically resolve dependencies based on what is imported in the script. It’s mainly useful for quick demos, POCs, and internal tooling, not for most production services where teams prefer Maven/Gradle builds.
To run using Boot CLI, install the CLI, write a simple Groovy script, and run it using the spring run command. Boot CLI compiles the script, resolves dependencies, and starts the embedded server.
Example app.groovy:
@RestController
class HelloController {
@RequestMapping("/")
String home() {
"Hello from Boot CLI"
}
}
Run it:
spring run app.groovy
For an existing project, CLI is less common. Most teams execute with Maven/Gradle. But CLI can still run a script-style Spring app quickly during interviews and demos.
32) How is Spring Security implemented in a Spring Boot application?
Spring Boot implements Spring Security through auto-configuration. Adding the security starter brings a default security filter chain that protects all endpoints and generates a default login form for browser-based flows. In real applications, that default is replaced with an explicit SecurityFilterChain configuration.
Implementation usually includes:
- Authentication mechanism (form login, basic auth, JWT, OAuth2)
- Authorization rules (role-based access, scope-based access)
- Password hashing (BCrypt)
- CSRF rules (enabled for browser sessions, disabled for stateless APIs)
- Method-level security for fine-grained control
Basic example using a modern SecurityFilterChain:
@Configuration
class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic(basic -> {})
.build();
}
}
33) How to disable a specific auto-configuration?
Sometimes auto-configuration creates beans that conflict with custom configuration. Spring Boot allows disabling auto-configuration at the application level or via properties.
Option 1: Exclude it from @SpringBootApplication:
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class
})
public class App {}
Option 2: Use properties to exclude by class name:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Disabling auto-configuration is common when building non-DB services, custom security setups, or when a library brings an auto-config that is not desired.
34) Difference between cache eviction and cache expiration?
Cache expiration is time-based. The cache entry becomes invalid after a configured TTL or time window. This is handled by the cache provider (Redis TTL, Caffeine expireAfterWrite, etc.). Expiration is useful when data becomes stale naturally after some time and strict consistency is not required.
Cache eviction is event-based or manual. The application removes entries when a change happens. For example, when a product is updated, the cached product entry should be evicted. Eviction is necessary when correctness matters and stale cached values are unacceptable.
Spring examples:
- Expiration: configured in provider (Caffeine/Redis)
- Eviction:
@CacheEvictin code
@CacheEvict(cacheNames = "products", key = "#id")
public void updateProduct(Long id) {
// update DB
}
35) Scaling Spring Boot for high traffic: what strategies would be used?
Scaling under high traffic is usually a combination of application optimization and infrastructure scaling. First, remove bottlenecks: optimize database queries, add caching, tune thread pools and connection pools, and reduce payload sizes through pagination and compression. Then scale horizontally by running multiple instances behind a load balancer.
Common scaling strategies:
- Horizontal scaling with stateless services
- Distributed caching (Redis) for shared cache
- Database scaling: read replicas, indexing, query optimization
- Async processing for long-running work (queues, events)
- Rate limiting at gateway
- CDN for static content
- Connection pooling tuning
- Circuit breakers for downstream services
For real traffic spikes, the most reliable strategy is stateless services + autoscaling + caching + resilient downstream calls.
36) Security in microservices architecture using Spring Boot and Spring Security
Microservices security normally uses a centralized identity provider. Instead of maintaining sessions between services, modern systems use token-based security such as OAuth2 + JWT.
Standard approach:
- API Gateway validates tokens and enforces coarse-grained rules
- Each microservice validates JWT as a resource server
- Service-to-service calls use mTLS and/or client credentials flow
- Use scopes/roles inside JWT for authorization
- Centralized auditing and consistent security policies
Example resource server configuration concept:
@Configuration
class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt())
.build();
}
}
This is the common “real interview” answer: JWT validation per service, not shared session state.
37) Session management in Spring Boot, especially in distributed systems
In single-instance applications, HTTP session storage in memory works. In distributed systems with multiple instances behind a load balancer, in-memory session breaks because requests may land on different nodes.
There are three typical solutions:
Stateless authentication (JWT) No session stored server-side. Best choice for APIs.
Sticky sessions Load balancer always routes the same user to the same instance. Works but reduces flexibility and resilience.
Distributed session store (Spring Session) Session data stored in Redis or JDBC so all instances share it. Good for traditional web apps that require server-side session.
Redis session example:
spring.session.store-type=redis
spring.data.redis.host=localhost
spring.data.redis.port=6379
This makes sessions portable across instances and supports scaling without sticky routing.
38) Multiple external APIs: handling rate limits and failures
External APIs fail in real life. A strong design includes resilience and throttling. This typically includes:
- Timeouts (never wait indefinitely)
- Retries with backoff (careful: retries can amplify load)
- Circuit breakers (stop calling when dependency is failing)
- Bulkheads (prevent one dependency from consuming all threads)
- Rate limiting (client-side and gateway-side)
- Caching responses where possible
- Fallback behavior when API is unavailable
Resilience4j is commonly used for this. Even without showing full configuration, the key is demonstrating a layered approach: protect threads, protect downstream, and degrade gracefully.
39) Externalized configuration and securing sensitive properties in microservices
Microservices should not carry environment-specific configs inside the code. Externalize configuration using environment variables, config maps, or centralized config services.
Common approaches:
- Environment variables for secrets
- Kubernetes Secrets mounted as env vars or files
- Secret managers: Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager
- Spring Cloud Config for centralized configuration (not a secret store by itself, usually combined with encryption or Vault)
Basic example:
spring.datasource.password=${DB_PASSWORD}
jwt.secret=${JWT_SECRET}
Secrets are injected by runtime environment, never committed.
40) Can a non-web application be created in Spring Boot?
Yes. Spring Boot is not only for web apps. It can run batch jobs, schedulers, event consumers, CLI tools, and background processors.
Typical non-web use cases:
- Kafka consumer service
- Batch processing with Spring Batch
- Scheduled jobs using
@Scheduled - ETL pipeline workers
To run as a non-web application:
spring.main.web-application-type=none
Example command-line runner:
@SpringBootApplication
public class JobApp {
public static void main(String[] args) {
SpringApplication.run(JobApp.class, args);
}
@Bean
CommandLineRunner runner() {
return args -> System.out.println("Non-web Spring Boot job running");
}
}
41) What does @SpringBootApplication do internally?
@SpringBootApplication is a convenience annotation. It combines three core annotations:
@Configuration@EnableAutoConfiguration@ComponentScan
@Configuration marks the class as a source of bean definitions.
@ComponentScan tells Spring to scan the current package and sub-packages for components like @Service, @Repository, and @Controller.
@EnableAutoConfiguration triggers Spring Boot’s auto-configuration mechanism.
Internally, auto-configuration works by loading configuration classes declared in metadata (in modern versions via AutoConfiguration.imports). Each configuration class contains conditional annotations like @ConditionalOnClass and @ConditionalOnMissingBean. Spring Boot evaluates these conditions and only creates beans when required dependencies are present.
In short, @SpringBootApplication bootstraps the entire application context and wires infrastructure automatically based on the classpath.
42) What is Spring Boot DevTool,s and how does it improve developer productivity?
Spring Boot DevTools improves development speed by enabling automatic restart and live reload.
When DevTools is added as a dependency, the application automatically restarts whenever classpath changes are detected. Instead of manually stopping and starting the application after every change, only the changed parts are reloaded. This significantly reduces feedback time.
DevTools also:
- Disables template caching during development
- Provides LiveReload integration for browser refresh
- Separates restart classloader from base classloader for faster restarts
Example dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
DevTools should not be included in production builds.
43) How can you mock external services in a Spring Boot test?
When testing services that call external APIs, direct network calls should be avoided. Instead, the HTTP client should be mocked.
Common approaches:
@MockBeanto replace the client bean- WireMock for HTTP-level mocking
- MockWebServer (for low-level testing)
Using @MockBean:
@SpringBootTest
class PaymentServiceTest {
@MockBean
private ExternalPaymentClient client;
@Autowired
private PaymentService paymentService;
@Test
void testPayment() {
Mockito.when(client.process()).thenReturn(true);
paymentService.makePayment();
}
}
This replaces the real bean inside the Spring context.
For integration-level HTTP mocking, WireMock is preferred.
44) How do you mock microservices during testing?
In microservices environments, mocking at the HTTP boundary is more realistic than mocking internal classes.
WireMock is commonly used to simulate another service. It runs a fake HTTP server that returns predefined responses. This allows full integration testing without requiring the real dependent service.
Example test with WireMock (conceptually):
// Start WireMock server
WireMockServer wireMockServer = new WireMockServer(8089);
wireMockServer.start();
WireMock.stubFor(
WireMock.get("/inventory/123")
.willReturn(WireMock.aResponse()
.withStatus(200)
.withBody("true"))
);
This approach verifies request structure and response handling at network level.
45) Explain the process of creating a Docker image for a Spring Boot application.
The process is straightforward:
- Build the application JAR using Maven or Gradle.
- Create a Dockerfile.
- Build Docker image.
- Run container.
Basic Dockerfile:
FROM eclipse-temurin:17-jdk-alpine
WORKDIR /app
COPY target/app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
Build image:
docker build -t springboot-app .
Run container:
docker run -p 8080:8080 springboot-app
For optimized images, multi-stage builds or layered jars can reduce size.
46) Discuss configuration of Spring Boot Security for common concerns
Common security concerns include:
- Authentication
- Authorization
- CSRF protection
- CORS configuration
- Password hashing
- Session management
- Protection against brute-force attacks
Security configuration typically includes defining a SecurityFilterChain and using a strong password encoder such as BCrypt.
Example:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.build();
}
Production systems often use OAuth2 or JWT instead of basic authentication.
47) How would you secure a Spring Boot application using JWT?
JWT-based security is stateless. After login, the server generates a signed token containing user identity and roles. The client sends this token in every request.
Flow:
- User authenticates.
- Server validates credentials.
- Server generates JWT and sends it back.
- Client includes JWT in Authorization header.
- Server validates JWT on each request.
JWT advantages:
- Stateless
- Scalable
- No server-side session storage required
Example header:
Authorization: Bearer <token>
Spring Security can be configured as a resource server to validate JWT tokens.
48) How cana Spring Boot application be made more resilient to failures?
Resilience is critical in distributed systems.
Common strategies:
- Timeouts on all external calls
- Retries with exponential backoff
- Circuit breakers (Resilience4j)
- Bulkhead isolation
- Rate limiting
- Health checks with Actuator
- Fallback mechanisms
- Distributed tracing for debugging
For example, a circuit breaker prevents repeated calls to a failing service, protecting system stability.
Resilience is not about eliminating failures — it is about limiting blast radius.
49) Explainthe conversion of business logic into serverless functions using Spring Cloud Function
Spring Cloud Function allows writing business logic as standalone functions and deploying them in different environments such as AWS Lambda, Azure Functions, or as HTTP endpoints.
Instead of writing a controller, define a Function<T, R> bean.
Example:
@Bean
public Function<String, String> uppercase() {
return value -> value.toUpperCase();
}
This function can run:
- As HTTP endpoint
- As AWS Lambda
- As event processor
It decouples business logic from transport mechanism.
50) How can Spring Cloud Gateway be configured for routing, security, and monitoring?
Spring Cloud Gateway acts as an API gateway in a microservices architecture.
Routing is defined using predicates and filters. It forwards requests to downstream services.
Example routing configuration:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/users/**
Security can be integrated with Spring Security or OAuth2. Gateway can validate JWT before forwarding requests.
Monitoring is handled via Actuator and Micrometer. Metrics such as request rate, response time, and status codes can be exported to Prometheus.
Gateway centralizes cross-cutting concerns:
- Authentication
- Rate limiting
- Logging
- Routing
- Circuit breaking
51) How would you manage and monitor asynchronous tasks in a Spring Boot application?
Asynchronous tasks should never be “fire-and-forget” in serious systems. They must be observable, traceable, and recoverable in case of failure.
The first step is defining a proper TaskExecutor with bounded thread pools instead of relying on defaults. Without limits, the system can exhaust resources under heavy load.
Monitoring can be achieved using:
- Spring Boot Actuator (thread pool metrics)
- Micrometer integration
- Logging correlation IDs
- Storing task status in a database for tracking progress
For failure handling:
- Use retries with backoff
- Capture exceptions and update task status
- Implement dead-letter mechanisms for persistent failures
Example configuration:
@EnableAsync
@Configuration
class AsyncConfig {
@Bean
public Executor taskExecutor() {
return new ThreadPoolExecutor(
5,
10,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100)
);
}
}
Example async method:
@Async
public CompletableFuture<String> processTask(Long taskId) {
try {
// business logic
return CompletableFuture.completedFuture("SUCCESS");
} catch (Exception e) {
// log and update DB
return CompletableFuture.completedFuture("FAILED");
}
}
In production, monitoring and status persistence are critical.
52) Processing notifications asynchronously using a message queue
For reliable asynchronous notifications, a message broker such as Kafka or RabbitMQ should be used.
The setup includes:
- Add messaging dependency.
- Configure broker connection.
- Create producer to publish messages.
- Create consumer to process messages.
- Handle retries and failures.
Example with RabbitMQ:
Configuration:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
Producer:
@Service
class NotificationProducer {
private final RabbitTemplate rabbitTemplate;
NotificationProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void sendNotification(String message) {
rabbitTemplate.convertAndSend("notificationQueue", message);
}
}
Consumer:
@Service
class NotificationConsumer {
@RabbitListener(queues = "notificationQueue")
public void receive(String message) {
System.out.println("Received: " + message);
}
}
In production, dead-letter queues and retry strategies must be configured.
53) Configure basic form-based authentication in Spring Security
Form-based authentication is commonly used for browser-based applications.
Steps:
- Add Spring Security dependency.
- Define a
SecurityFilterChain. - Configure login page and access rules.
- Define password encoder and user details.
Example:
@Configuration
class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.build();
}
@Bean
UserDetailsService userDetailsService() {
UserDetails user =
User.withUsername("user")
.password("{noop}password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
This sets up login page and protects all endpoints except /public.
54) How to tell auto-configuration to back away when a bean exists?
Spring Boot auto-configuration uses @ConditionalOnMissingBean. If a bean of the same type already exists, the auto-configured bean will not be created.
To override behavior, define a custom bean of the same type.
Example:
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
If Boot auto-configures ObjectMapper, defining a custom one causes auto-config to back off.
55) Integration of Spring Boot with CI/CD pipelines
Spring Boot integrates easily with CI/CD systems like GitHub Actions, GitLab CI, Jenkins, or Azure DevOps.
Typical pipeline steps:
- Checkout code.
- Run unit tests.
- Run integration tests.
- Build artifact (JAR).
- Build Docker image.
- Push image to registry.
- Deploy to Kubernetes or cloud environment.
Example pipeline step (conceptually):
mvn clean verify
docker build -t app:latest .
docker push registry/app:latest
kubectl apply -f deployment.yaml
Spring Boot’s fast startup and self-contained jar structure simplify automation.
56) Can we override or replace embedded Tomcat?
Yes.
Spring Boot selects embedded server based on classpath dependencies. Tomcat is default. To replace it, exclude Tomcat and include another server starter.
Example for Jetty:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Spring Boot auto-detects Jetty and configures it automatically.
57) How to resolve White Label error page?
White Label error page appears when no custom error mapping exists.
To resolve:
- Create custom error page in
resources/templates/error.html - Implement
@ControllerAdvicefor global exception handling - Disable default error page if needed
Example global handler:
@ControllerAdvice
class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handle(Exception e) {
return ResponseEntity.status(500).body("Internal Server Error");
}
}
58) How to implement pagination?
Spring Data JPA supports pagination using Pageable.
Repository:
Page<User> findAll(Pageable pageable);
Controller:
@GetMapping("/users")
public Page<User> getUsers(
@RequestParam int page,
@RequestParam int size) {
return repository.findAll(PageRequest.of(page, size));
}
Pagination prevents returning large datasets and improves performance.
59) How to handle 404 error in Spring Boot?
A 404 occurs when no endpoint matches a request.
Custom handling can be done using @ControllerAdvice and overriding error handling.
Example:
@ControllerAdvice
class NotFoundHandler {
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<String> handleNotFound() {
return ResponseEntity.status(404).body("Resource not found");
}
}
Additionally:
spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false
60) How can Spring Boot implement event-driven architecture?
Spring Boot supports event-driven architecture using:
- Application events (
ApplicationEventPublisher) - Messaging systems (Kafka, RabbitMQ)
- Spring Cloud Stream
Internal event example:
@Component
class OrderService {
private final ApplicationEventPublisher publisher;
OrderService(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void createOrder() {
publisher.publishEvent(new OrderCreatedEvent(this));
}
}
Listener:
@Component
class OrderListener {
@EventListener
public void handle(OrderCreatedEvent event) {
System.out.println("Order created event received");
}
}
For distributed systems, messaging brokers are preferred over local events.
My Top and Bestseller Udemy Courses. The sale is going on with a 70 - 80% discount. The discount coupon has been added to each course below:
Build REST APIs with Spring Boot 4, Spring Security 7, and JWT
[NEW] Learn Apache Maven with IntelliJ IDEA and Java 25
ChatGPT + Generative AI + Prompt Engineering for Beginners
Spring 7 and Spring Boot 4 for Beginners (Includes 8 Projects)
Available in Udemy for Business
Building Real-Time REST APIs with Spring Boot - Blog App
Available in Udemy for Business
Building Microservices with Spring Boot and Spring Cloud
Available in Udemy for Business
Java Full-Stack Developer Course with Spring Boot and React JS
Available in Udemy for Business
Build 5 Spring Boot Projects with Java: Line-by-Line Coding
Testing Spring Boot Application with JUnit and Mockito
Available in Udemy for Business
Spring Boot Thymeleaf Real-Time Web Application - Blog App
Available in Udemy for Business
Master Spring Data JPA with Hibernate
Available in Udemy for Business
Spring Boot + Apache Kafka Course - The Practical Guide
Available in Udemy for Business
Comments
Post a Comment
Leave Comment