Spring Boot Tricky Interview Questions & Answers #2
This guide contains challenging interview questions and detailed answers focused on Spring Boot, designed to test practical experience and advanced conceptual understanding.
1. Spring Boot Internals & Configuration
Q: How to get the list of all the beans in your Spring Boot application?
A: Two approaches โ programmatic and via Actuator:
// 1. Programmatic โ autowire ApplicationContext
@Component
public class BeanLister implements CommandLineRunner {
@Autowired ApplicationContext context;
@Override
public void run(String... args) {
String[] beanNames = context.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String name : beanNames) {
System.out.printf("%-40s โ %s%n", name, context.getBean(name).getClass().getName());
}
// Output: dataSource โ com.zaxxer.hikari.HikariDataSource
}
}
# 2. Actuator endpoint (requires management.endpoints.web.exposure.include=beans)
curl http://localhost:8080/actuator/beans | jq '.contexts[].beans | keys'
The Actuator response also shows bean scope (singleton/prototype), type, resource (where defined), and dependencies โ useful for debugging wiring issues.
Q: Explain the concept of Spring Boot's embedded servlet containers.
A: Spring Boot bundles a web server inside the application JAR โ no external Tomcat/JBoss installation needed:
| Server | Default for | Model | Use Case |
|---|---|---|---|
| Tomcat | spring-boot-starter-web | Thread-per-request | General purpose (95% of apps) |
| Jetty | โ | Thread-per-request | Lightweight, good WebSocket support |
| Undertow | โ | Non-blocking I/O | High-throughput, Red Hat ecosystem |
| Netty | spring-boot-starter-webflux | Event-loop | Reactive applications |
The embedded server is configured programmatically via application.yml:
server:
port: 8080
tomcat:
threads:
max: 200 # Worker threads (default: 200)
min-spare: 10 # Minimum idle threads
max-connections: 8192 # Max TCP connections accepted
accept-count: 100 # OS-level backlog queue
connection-timeout: 20s # Connection idle timeout
Thread pool sizing tip: Using Little's Law โ
threads_needed = throughput ร latency. For 300 RPS with 50ms avg response:300 ร 0.05 = 15 threads. Setthreads.maxto 2-3ร this for burst headroom.
Q: How does Spring Boot make Dependency Injection (DI) easier compared to traditional Spring?
A:
| Aspect | Traditional Spring | Spring Boot |
|---|---|---|
| Bean definition | XML: <bean class="..."> or @Bean | Auto-detected via @Component, @Service, @Repository |
| Wiring | Explicit <property ref="..."> | Auto-wired by type (constructor injection preferred) |
| Configuration | Manual DataSource, TransactionManager, etc. | Auto-configured from classpath + properties |
| 3rd party setup | Write @Configuration classes | Starter POMs + auto-configuration |
Under the hood: @ComponentScan (part of @SpringBootApplication) scans packages recursively. For each @Component-annotated class, Spring creates a BeanDefinition, resolves constructor parameters by type, and injects them. Constructor injection is preferred (and implicit since Spring 4.3 for single-constructor classes) โ it makes dependencies explicit and allows final fields:
@Service
public class OrderService {
private final OrderRepository orderRepo; // final โ immutable
private final PaymentGateway paymentGateway;
// Single constructor โ @Autowired is implicit
public OrderService(OrderRepository orderRepo, PaymentGateway paymentGateway) {
this.orderRepo = orderRepo;
this.paymentGateway = paymentGateway;
}
}
Q: How does Spring Boot simplify the management of application secrets and sensitive configurations?
A: Layered approach, from simple to enterprise:
-
Environment variables:
SPRING_DATASOURCE_PASSWORD=secretโ overridesspring.datasource.password. Works with Docker, Kubernetes secrets. -
application-{profile}.yml: Profile-specific configs in Git (dev/staging/prod). Never commit real secrets to Git. -
Spring Cloud Config Server: Centralized config backed by Git, with encryption support:
spring.datasource.password: '{cipher}AQBxxxxEncryptedxxxx' -
HashiCorp Vault integration:
spring.cloud.vault:uri: https://vault.company.comkv:backend: secretdefault-context: myappThe
spring-cloud-starter-vault-configdependency auto-injects Vault secrets as Spring properties at startup โ zero code changes. -
Kubernetes Secrets: Mounted as environment variables or files, read via
@Value("${DB_PASSWORD}").
Q: Explain Spring Boot's approach to handle asynchronous operations.
A: Spring Boot's @Async annotation runs methods on a separate thread pool:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("taskExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // Minimum threads
executor.setMaxPoolSize(20); // Maximum threads
executor.setQueueCapacity(100); // Queue before creating new threads
executor.setThreadNamePrefix("async-");
executor.setRejectedExecutionHandler(new CallerRunsPolicy()); // Backpressure
executor.initialize();
return executor;
}
}
@Service
public class NotificationService {
@Async("taskExecutor")
public CompletableFuture<String> sendEmail(String to, String body) {
// Runs on async-* thread, not the Tomcat worker thread
emailClient.send(to, body);
return CompletableFuture.completedFuture("sent");
}
}
Critical self-invocation trap:
@Async(like@Transactional,@Cacheable) is proxy-based. Callingthis.sendEmail()from within the same class bypasses the proxy โ the method runs synchronously on the caller's thread. Fix: Inject the service into itself via constructor, or extract to a separate bean.
Q: How can you enable and use asynchronous methods in a Spring Boot application?
A:
- Add
@EnableAsyncto a configuration class. - Define a custom
ThreadPoolTaskExecutorbean (avoid the defaultSimpleAsyncTaskExecutorwhich creates unlimited threads). - Annotate target methods with
@Async("executorBeanName"). - Return
CompletableFuture<T>if the caller needs the result, orvoidfor fire-and-forget. - Handle exceptions via
AsyncUncaughtExceptionHandler(for void methods) or.exceptionally()onCompletableFuture.
2. Security & Authentication
Q: Describe how you would secure sensitive data in a Spring Boot application accessed by multiple users with different roles.
A: Defense-in-depth approach:
| Layer | Mechanism | Implementation |
|---|---|---|
| Authentication | Verify identity | Spring Security + JWT/OAuth2 |
| Authorization | Role-based access | @PreAuthorize("hasRole('ADMIN')") |
| Data encryption at rest | Protect stored data | AES-256 via Jasypt or DB-level TDE |
| Data encryption in transit | Protect network traffic | HTTPS/TLS (mandatory in production) |
| Secret management | Keep credentials safe | Vault, K8s Secrets, env vars |
| Audit trail | Track access | Spring Data Auditing + @CreatedBy |
// Role-based method security
@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
public UserProfile getUserProfile(Long userId) { ... }
// Data masking in logs
@ToString(exclude = {"ssn", "creditCard"}) // Lombok
public class User { ... }
Q: Can you explain the difference between Authentication and Authorization in Spring Security?
A:
| Aspect | Authentication | Authorization |
|---|---|---|
| Question | Who are you? | What can you do? |
| Mechanism | Credentials verification | Permission/role checks |
| When | Before authorization | After authentication |
| Spring component | AuthenticationManager + AuthenticationProvider | AccessDecisionManager + SecurityExpressionHandler |
| Failure response | 401 Unauthorized | 403 Forbidden |
| Storage | SecurityContext.getAuthentication() | GrantedAuthority collection |
Q: How is Spring Security implemented in a Spring Boot application?
A: Modern Spring Security (Spring Boot 3.x) uses component-based configuration โ WebSecurityConfigurerAdapter is deprecated:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // Enables @PreAuthorize, @PostAuthorize
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // Disable for stateless APIs
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // 12 rounds โ ~250ms hash time
}
}
Filter chain execution order:
SecurityContextPersistenceFilterโCsrfFilterโLogoutFilterโUsernamePasswordAuthenticationFilterโExceptionTranslationFilterโFilterSecurityInterceptor. Your custom JWT filter is inserted beforeUsernamePasswordAuthenticationFilter.
Q: Describe how to implement security in a Microservices architecture using Spring Boot.
A: The API Gateway pattern centralizes security:
| Architecture Component | Role in Security Model | Validation Responsibility | Inter-Service Protocol |
|---|---|---|---|
| Identity Provider (Auth Service) | OAuth 2.0 / OIDC Provider | Authenticates users, validates credentials/MFA, signs JWT tokens with private key. | Public key JWKS endpoint |
| API Gateway (Edge Router) | Single public ingress | Validates JWT signature, checks expiration, extracts roles, rate limits. Unauthenticated requests rejected with HTTP 401. | TLS termination |
| Downstream Microservices (A, B, C, D) | Protected business logic | Trusts Gateway claims (X-User-Id, X-User-Roles) passed via headers; verifies fine-grained method authorization (@PreAuthorize). | Internal mTLS mesh |
- Auth Service authenticates users and issues signed JWT tokens.
- API Gateway (Spring Cloud Gateway) validates JWT signature on every request. Invalid tokens โ
401. - Downstream services trust the gateway โ they extract user claims from the JWT header without re-validating the signature (or validate with the same public key for extra security).
- mTLS (mutual TLS) secures inter-service communication.
3. Deployment & Scaling
Q: If you had to scale a Spring Boot application to handle high traffic, what strategies would you use?
A:
| Strategy | What It Solves | Implementation |
|---|---|---|
| Horizontal scaling | CPU/memory exhaustion | Kubernetes replicas + HPA |
| Connection pooling | DB connection exhaustion | HikariCP (maximumPoolSize) |
| Caching | Repetitive DB queries | Redis/Caffeine + @Cacheable |
| Async processing | Thread blocking on I/O | @Async, message queues |
| Read replicas | DB read bottleneck | Spring @Transactional(readOnly=true) routes to replica |
| CDN | Static asset latency | CloudFront/CloudFlare |
| Rate limiting | Abuse/DDoS | Bucket4j, Spring Cloud Gateway |
Capacity planning with Little's Law:
Concurrent users = Arrival rate ร Average response time
Example: 1000 RPS ร 0.1s = 100 concurrent requests
โ Need 100+ Tomcat threads + proportional DB connections
Q: In Spring Boot, how is Session Management configured in distributed systems?
A: Spring Session externalizes session data:
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
# application.yml
spring:
session:
store-type: redis
timeout: 30m
redis:
host: redis-cluster.internal
port: 6379
Spring Session intercepts HttpSession operations via a SessionRepositoryFilter, transparently storing/retrieving session data from Redis instead of server memory. All application instances share the same Redis โ a user's session persists across any server they hit.
Alternative for stateless APIs: Don't use sessions at all. Use JWT โ the client carries its own authentication state. This is the preferred approach for microservices.
4. File Handling, Email & CLI
Q: You are creating an endpoint that allows users to upload files. How would you handle it?
A:
@RestController
public class FileController {
@PostMapping("/api/upload")
public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) return ResponseEntity.badRequest().body("No file");
if (file.getSize() > 10_000_000) return ResponseEntity.status(413).body("Too large");
// Stream to S3 (don't load entire file into memory)
s3Client.putObject(PutObjectRequest.builder()
.bucket("my-bucket").key(file.getOriginalFilename()).build(),
RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
return ResponseEntity.ok("Uploaded: " + file.getOriginalFilename());
}
}
# application.yml โ configure file upload limits
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
file-size-threshold: 2KB # Files larger than 2KB written to temp disk
Production tip: Never store uploads on local disk in a scaled deployment โ instances are ephemeral. Use object storage (S3, GCS, MinIO).
Q: After registration, your application needs to send a welcome email. How?
A:
@Service
public class EmailService {
private final JavaMailSender mailSender;
@Async("taskExecutor") // Send asynchronously โ don't block registration
public void sendWelcomeEmail(String to, String name) {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(to);
helper.setSubject("Welcome, " + name + "!");
helper.setText(buildHtmlTemplate(name), true); // HTML content
mailSender.send(message);
}
}
Resilience: Email servers can be down. In production, use a message queue (Kafka/RabbitMQ) between your app and the email sender. The registration flow publishes a
UserRegisteredEvent, and a separate consumer handles email delivery with retries.
Q: How do you disable a specific Auto-configuration class?
A:
// Method 1: Annotation exclude
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
SecurityAutoConfiguration.class
})
public class MyApplication { }
// Method 2: Property-based exclude
// application.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Q: Explain the difference between Cache Eviction and Cache Expiration.
A:
| Aspect | Cache Eviction | Cache Expiration |
|---|---|---|
| Trigger | Cache is full (space pressure) | Entry age exceeds TTL |
| Purpose | Manage cache size | Ensure data freshness |
| Policy | LRU, LFU, FIFO, Random | Time-based (TTL, TTI) |
| Example | Caffeine maximumSize(1000) โ evicts LRU entry when 1001st added | Redis EXPIRE key 3600 โ entry dies after 1 hour |
| Data loss | Potentially useful data removed | Stale data removed |
In practice, you configure both: size-based eviction (prevent OOM) + time-based expiration (prevent stale reads).
Q: How would you manage externalized configuration in a microservice architecture?
A: Spring Cloud Config Server provides centralized config:
| Subsystem Component | Role in Centralized Config | Storage / Backing Backend | Dynamic Refresh Mechanism |
|---|---|---|---|
| Spring Cloud Config Server | Centralized configuration authority | Version-controlled Git repository or HashiCorp Vault. | Serves {app}-{profile}.yml via REST APIs. |
| Microservices (User, Order, Payment) | Configuration consumers | Fetches bootstrap configuration on application startup. | Spring Cloud Bus / Kafka webhook triggers @RefreshScope reload. |
| Secrets Engine (Vault / AWS Secrets) | Secret encryption & key rotation | Hardware security module / KMS encryption. | Config server /encrypt and /decrypt endpoints. |
- Each service has
bootstrap.ymlpointing to Config Server. - Config Server serves
{application-name}-{profile}.ymlfrom Git. - Sensitive values: Encrypt with Config Server's
/encryptendpoint, or integrate Vault. - Runtime refresh:
@RefreshScopebeans re-read config when/actuator/refreshis called โ no restart needed.
