Spring Boot Interview Questions Guide: For 8+ Years Experienced Java Developers
Spring Boot Interview Questions Guide: For 8+ Years Experienced Java Developers
Questions Guide
For 8+ Years Experienced Java
Developers
Comprehensive Interview Preparation Resource
Updated: March 2026
Table of Contents
1. Core Spring Boot Concepts
2. Spring Boot 3.x New Features
3. Auto-Configuration and Dependency Management
4. RESTful API Design and Best Practices
5. Microservices Architecture
6. Spring Boot Security
7. Data Access and JPA
8. Transaction Management
9. Performance Optimization
10. Messaging and Event-Driven Architecture
11. Monitoring, Observability, and Actuator
12. Testing Strategies
13. Deployment and DevOps
14. Design Patterns and Best Practices
15. Scenario-Based Questions
Key Differences:
@Bean
@ConditionalOnMissingBean
public DataSource dataSource() {
return new HikariDataSource();
}
Starters are dependency descriptors that bring in all necessary dependencies for
a specific functionality with compatible versions.
Common Starters:
Starter Purpose
Benefits:
Limitations:
@GetExchange("/users/{id}")
User getUserById(@PathVariable Long id);
@PostExchange("/users")
User createUser(@RequestBody User user);
@DeleteExchange("/users/{id}")
void deleteUser(@PathVariable Long id);
Configuration:
@Configuration
public class HttpClientConfig {
@Bean
public UserClient userClient() {
WebClient webClient = [Link]()
.baseUrl("[Link]
.build();
return [Link]([Link]);
}
3. Auto-Configuration and
Dependency Management
Q8. How do you exclude specific auto-
configuration classes?
Answer:
1. Using @SpringBootApplication:
@SpringBootApplication(exclude = {
[Link],
[Link]
})
public class MyApplication {
}
2. Using [Link]:
[Link]=
[Link],
[Link]
n
3. Using @EnableAutoConfiguration:
@Configuration
@EnableAutoConfiguration(exclude = {[Link]})
public class AppConfig {
}
@Bean
@ConditionalOnMissingBean
public MyService myService(MyServiceProperties properties) {
return new MyService(properties);
}
4. Register auto-configuration in
META-INF/spring/[Link]
[Link]:
[Link]
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 {
@GetMapping("/{id}")
public UserV2 getUser(@PathVariable Long id) {
return userService.getUserV2(id);
}
}
2. Header Versioning:
@RestController
@RequestMapping("/api/users")
public class UserController {
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleResourceNotFound(
ResourceNotFoundException ex,
WebRequest request) {
[Link]("Resource not found: {}", [Link]());
return [Link]()
.timestamp([Link]())
.status(HttpStatus.NOT_FOUND.value())
.error("Resource Not Found")
.message([Link]())
.path([Link](false))
.build();
}
@ExceptionHandler([Link])
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ValidationErrorResponse handleValidationException(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
[Link]().getFieldErrors().forEach(error ->
[Link]([Link](), [Link]())
);
return new ValidationErrorResponse(
[Link](),
HttpStatus.BAD_REQUEST.value(),
"Validation Failed",
errors
);
}
@ExceptionHandler([Link])
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleGlobalException(Exception ex) {
[Link]("Unexpected error occurred", ex);
return [Link]()
.timestamp([Link]())
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
.error("Internal Server Error")
.message("An unexpected error occurred")
.build();
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
public ResponseEntity<PagedResponse<UserDTO>> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(defaultValue = "id,asc") String[] sort) {
return [Link](response);
}
Best Practices:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public EntityModel<UserDTO> getUser(@PathVariable Long id) {
UserDTO user = [Link](id);
return resource;
}
@GetMapping
public CollectionModel<EntityModel<UserDTO>> getAllUsers() {
List<EntityModel<UserDTO>> users = [Link]()
.stream()
.map(user -> [Link](user,
linkTo(methodOn([Link])
.getUser([Link]())).withSelfRel()))
.collect([Link]());
return [Link](users,
linkTo(methodOn([Link])
.getAllUsers()).withSelfRel());
}
Dependency:
[Link] spring-boot-starter-hateoas
5. Microservices Architecture
Q15. How do you design a microservices
architecture using Spring Boot?
Answer:
Component Responsibility
Configuration:
resilience4j:
circuitbreaker:
instances:
userService:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 5s
failureRateThreshold: 50
slowCallRateThreshold: 100
slowCallDurationThreshold: 2s
Implementation:
@Service
@Slf4j
public class OrderService {
@Autowired
private UserServiceClient userServiceClient;
States:
Dependencies:
[Link] micrometer-tracing-bridge-brave [Link].reporter2 zipkin-
reporter-brave
Configuration:
management:
tracing:
sampling:
probability: 1.0
zipkin:
tracing:
endpoint: [Link]
Custom Spans:
@Service
public class OrderService {
@Autowired
private Tracer tracer;
// Business logic
Order order = createOrder(request);
[Link]("result", "success");
return order;
} catch (Exception e) {
[Link]("error", [Link]());
throw e;
} finally {
[Link]();
}
}
@Autowired
private KafkaTemplate<String, Object> kafkaTemplate;
@Transactional
public void createOrder(OrderRequest request) {
// Local transaction 1: Create order
Order order = [Link](new Order(request));
@KafkaListener(topics = "payment-completed")
public void handlePaymentCompleted(PaymentCompletedEvent event) {
Order order = [Link]([Link]())
.orElseThrow();
[Link](OrderStatus.PAYMENT_COMPLETED);
[Link](order);
// Continue saga
[Link]("reserve-inventory",
new ReserveInventoryEvent([Link](), [Link]()));
}
@KafkaListener(topics = "payment-failed")
public void handlePaymentFailed(PaymentFailedEvent event) {
// Compensating transaction
Order order = [Link]([Link]())
.orElseThrow();
[Link]([Link]);
[Link](order);
// Notify user
[Link]("order-cancelled",
new OrderCancelledEvent([Link]()));
}
@Autowired
private PaymentService paymentService;
@Autowired
private InventoryService inventoryService;
@Autowired
private ShippingService shippingService;
try {
// Step 1: Process payment
Payment payment = [Link](
[Link](), [Link]());
[Link]([Link]);
return [Link](order);
} catch (PaymentException e) {
cancelOrder(order);
throw new OrderException("Payment failed", e);
} catch (InventoryException e) {
compensatePayment(order);
cancelOrder(order);
throw new OrderException("Inventory unavailable", e);
} catch (ShippingException e) {
compensateInventory(order);
compensatePayment(order);
cancelOrder(order);
throw new OrderException("Shipping failed", e);
}
}
@Value("${[Link]}")
private String jwtSecret;
@Value("${[Link]}")
private long jwtExpiration;
return [Link]()
.setClaims(claims)
.setSubject([Link]())
.setIssuedAt(new Date())
.setExpiration(new Date([Link]() + jwtExpiration))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}
@Autowired
private JwtTokenProvider tokenProvider;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if ([Link](token, userDetails)) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails,
null,
[Link]()
);
[Link](
new WebAuthenticationDetailsSource()
.buildDetails(request)
);
[Link]()
.setAuthentication(authentication);
}
} catch (Exception e) {
[Link]("Cannot set user authentication", e);
}
}
[Link](request, response);
}
Security Configuration:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Autowired
private JwtAuthenticationFilter jwtAuthFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http
.csrf(csrf -> [Link]())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy([Link])
)
.addFilterBefore(jwtAuthFilter,
[Link]);
return [Link]();
}
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration config) throws Exception {
return [Link]();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/user/**")
.hasAuthority("SCOPE_user.read")
.requestMatchers("/api/admin/**")
.hasAuthority("SCOPE_admin")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> [Link](
jwtAuthenticationConverter()))
);
return [Link]();
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter =
new JwtGrantedAuthoritiesConverter();
[Link]("roles");
[Link]("ROLE_");
JwtAuthenticationConverter jwtAuthenticationConverter =
new JwtAuthenticationConverter();
[Link](
grantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}
Configuration:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: [Link]
jwk-set-uri: [Link]
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN')")
public List<User> getAllUsers() {
return [Link]();
}
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
public User getUserById(Long id) {
return [Link](id)
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
}
@PreAuthorize("#username == [Link] or
hasRole('ADMIN')")
public User updateUser(String username, UserUpdateRequest request) {
User user = [Link](username)
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
// Update logic
return [Link](user);
}
@PostAuthorize("[Link] ==
[Link]")
public User loadUserDetails(Long id) {
return [Link](id)
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
}
@PreAuthorize("@[Link](#userId)")
public User getUser(Long userId) {
return [Link](userId)
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
}
@Component("userSecurity")
public class UserSecurityService {
Problem Example:
// This causes N+1 queries
List<Department> departments = [Link]();
[Link](dept -> {
[Link]([Link]().size()); // Triggers N queries
});
Solutions:
1. Entity Graph:
@Entity
public class Department {
@Id
private Long id;
@EntityGraph(attributePaths = {"employees"})
List<Department> findAll();
3. Batch Fetching:
@Entity
public class Department {
@Id
private Long id;
@OneToMany(mappedBy = "department")
@BatchSize(size = 10)
private List<Employee> employees;
4. DTO Projection:
public interface DepartmentRepository extends JpaRepository<Department,
Long> {
Enable Auditing:
@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaConfig {
@Bean
public AuditorAware<String> auditorProvider() {
return new AuditorAwareImpl();
}
@Override
public Optional<String> getCurrentAuditor() {
Authentication authentication = SecurityContextHolder
.getContext().getAuthentication();
return [Link]([Link]());
}
@CreatedBy
@Column(updatable = false)
protected U createdBy;
@CreatedDate
@Column(updatable = false)
protected LocalDateTime createdDate;
@LastModifiedBy
protected U lastModifiedBy;
@LastModifiedDate
protected LocalDateTime lastModifiedDate;
@Version
protected Long version;
Entity Usage:
@Entity
@Table(name = "users")
public class User extends Auditable<String> {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
@Version
private Long version;
@Service
public class ProductService {
@Transactional
public Product updateProductPrice(Long id, BigDecimal newPrice) {
try {
Product product = [Link](id)
.orElseThrow(() -> new ResourceNotFoundException("Product not
found"));
[Link](newPrice);
return [Link](product);
} catch (OptimisticLockException e) {
throw new ConcurrentModificationException(
"Product was updated by another transaction");
}
}
Pessimistic Locking:
public interface ProductRepository extends JpaRepository<Product, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Product p WHERE [Link] = :id")
Optional<Product> findByIdWithWriteLock(@Param("id") Long id);
@Lock(LockModeType.PESSIMISTIC_READ)
@Query("SELECT p FROM Product p WHERE [Link] = :id")
Optional<Product> findByIdWithReadLock(@Param("id") Long id);
@Service
public class InventoryService {
@Transactional
public void decrementStock(Long productId, int quantity) {
// Acquires database lock
Product product = productRepository
.findByIdWithWriteLock(productId)
.orElseThrow(() -> new ResourceNotFoundException("Product not
found"));
[Link]([Link]() - quantity);
[Link](product);
// Lock released when transaction completes
}
Comparison:
8. Transaction Management
Q25. Explain Spring's transaction propagation
levels with examples.
Answer:
Propagation Behavior
Join existing transaction or create
REQUIRED (default)
new one
Always create new transaction,
REQUIRES_NEW
suspend current
Must run within existing transaction,
MANDATORY
else throw exception
Execute within nested transaction if
NESTED
current exists
Join transaction if exists, else run
SUPPORTS
non-transactional
Execute non-transactionally, suspend
NOT_SUPPORTED
current transaction
Execute non-transactionally, throw
NEVER
exception if transaction exists
@Service
public class OrderService {
@Autowired
private PaymentService paymentService;
@Autowired
private NotificationService notificationService;
@Transactional(propagation = [Link])
public void createOrder(OrderRequest request) {
// Transaction T1 starts here
Order order = [Link](new Order(request));
// Joins T1 (REQUIRED)
[Link](order);
@Service
public class PaymentService {
@Transactional(propagation = [Link])
public void processPayment(Order order) {
// Joins existing transaction from OrderService
Payment payment = new Payment(order);
[Link](payment);
@Service
public class NotificationService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendConfirmation(Order order) {
// Creates new independent transaction
// Suspends OrderService transaction temporarily
Notification notification = new Notification(order);
[Link](notification);
[Link](notification);
@Service
public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logActivity(String action, String details) {
// Always create new transaction for audit log
// Ensures audit is saved even if parent transaction fails
AuditLog log = new AuditLog(action, details, [Link]());
[Link](log);
}
@Service
public class ReportService {
Blocking protocol
Poor performance and scalability
Single point of failure
2. Saga Pattern (Recommended):
See Q18 for detailed implementation.
3. Event Sourcing:
@Service
public class OrderEventSourceService {
@Autowired
private EventStore eventStore;
[Link](event);
publishEvent(event);
return buildOrderFromEvents([Link]());
}
[Link](event -> {
if (event instanceof OrderCreatedEvent) {
[Link]((OrderCreatedEvent) event);
} else if (event instanceof PaymentProcessedEvent) {
[Link]((PaymentProcessedEvent) event);
}
// ... handle other events
});
return order;
}
@Autowired
private OrderRepository orderRepository;
@Autowired
private OutboxRepository outboxRepository;
@Transactional
public Order createOrder(OrderRequest request) {
// Single local transaction
Order order = [Link](new Order(request));
[Link](event);
return order;
}
@Scheduled(fixedDelay = 1000)
@Transactional
public void publishPendingEvents() {
List<OutboxEvent> events = outboxRepository
.findByPublishedFalseOrderByCreatedAtAsc(
[Link](0, 100));
[Link](event -> {
try {
[Link]([Link](), [Link]());
[Link](true);
[Link]([Link]());
[Link](event);
} catch (Exception e) {
[Link]("Failed to publish event: {}", [Link](), e);
[Link]([Link]() + 1);
[Link](event);
}
});
}
9. Performance Optimization
Q27. How do you optimize Spring Boot
application performance?
Answer:
2. Caching:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager(
"users", "products", "categories");
[Link]([Link]()
.expireAfterWrite(10, [Link])
.maximumSize(1000));
return cacheManager;
}
}
@Service
public class UserService {
@Caching(evict = {
@CacheEvict(value = "users", allEntries = true),
@CacheEvict(value = "userStats", allEntries = true)
})
public void refreshCache() {
// Evicts multiple caches
}
3. Async Processing:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
[Link](5);
[Link](10);
[Link](100);
[Link]("async-");
[Link]();
return executor;
}
@Service
public class NotificationService {
@Async("taskExecutor")
public CompletableFuture<Void> sendEmailAsync(String to, String subject) {
// Long-running operation
[Link](to, subject, body);
return [Link](null);
}
@Async
public void processLargeDataset(List<Data> dataset) {
// Process in background
[Link](this::process);
}
4. Database Optimization:
// Use projections instead of full entities
public interface UserProjection {
Long getId();
String getUsername();
String getEmail();
}
List<UserProjection> findAllProjectedBy();
5. Lazy Initialization:
spring:
main:
lazy-initialization: true # Use selectively
6. HTTP/2 Support:
server:
http2:
enabled: true
compression:
enabled: true
mime-types: application/json,application/xml,text/html,text/xml,text/plain
min-response-size: 1024
2. Write-Through:
@Service
public class ProductService {
3. Write-Behind:
@Service
public class ProductService {
@Autowired
private CacheManager cacheManager;
@Async
public void updateProductAsync(Product product) {
// Update cache immediately
Cache cache = [Link]("products");
[Link]([Link](), product);
4. Refresh-Ahead:
@Component
public class CacheRefresher {
@Scheduled(fixedDelay = 300000) // 5 minutes
public void refreshPopularProducts() {
List<Long> popularProductIds = analyticsService
.getPopularProductIds();
[Link](id ->
[Link](id)); // Warms cache
}
5. Multi-Level Caching:
@Configuration
public class CacheConfig {
@Bean
@Primary
public CacheManager compositeCacheManager() {
CompositeCacheManager cacheManager = new
CompositeCacheManager();
[Link](managers);
[Link](false);
return cacheManager;
}
@Bean
public CacheManager caffeineLocalCache() {
// L1 cache: Fast, local memory
CaffeineCacheManager manager = new CaffeineCacheManager();
[Link]([Link]()
.expireAfterWrite(5, [Link])
.maximumSize(1000));
return manager;
}
@Bean
public CacheManager redisCacheManager() {
// L2 cache: Distributed, shared across instances
RedisCacheConfiguration config = RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl([Link](30));
return [Link](redisConnectionFactory())
.cacheDefaults(config)
.build();
}
Configuration:
spring:
kafka:
bootstrap-servers: localhost:9092
consumer:
group-id: order-service
auto-offset-reset: earliest
key-deserializer: [Link]
value-deserializer:
[Link]
properties:
[Link]: [Link]
producer:
key-serializer: [Link]
value-serializer: [Link]
acks: all
retries: 3
Producer:
@Service
@Slf4j
public class OrderEventProducer {
@Autowired
private KafkaTemplate<String, OrderEvent> kafkaTemplate;
Consumer:
@Component
@Slf4j
public class OrderEventConsumer {
@Autowired
private NotificationService notificationService;
@KafkaListener(
topics = "order-created",
groupId = "notification-service",
containerFactory = "kafkaListenerContainerFactory"
)
public void handleOrderCreated(
@Payload OrderEvent event,
@Header(KafkaHeaders.RECEIVED_PARTITION) int partition,
@Header([Link]) long offset) {
try {
[Link](event);
} catch (Exception e) {
[Link]("Error processing order event: {}", [Link]());
throw e; // Triggers retry or DLQ
}
}
@KafkaListener(topics = "order-created")
public void handleOrderCreatedBatch(
List<OrderEvent> events,
Acknowledgment acknowledgment) {
[Link](event -> {
try {
processEvent(event);
} catch (Exception e) {
[Link]("Failed to process event: {}", event, e);
}
});
[Link]();
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, OrderEvent>
kafkaListenerContainerFactory() {
return factory;
}
@Bean
public DefaultErrorHandler errorHandler() {
// Retry with exponential backoff
BackOff backOff = new ExponentialBackOffWithMaxRetries(3);
((ExponentialBackOffWithMaxRetries) backOff).setInitialInterval(1000L);
((ExponentialBackOffWithMaxRetries) backOff).setMultiplier(2.0);
((ExponentialBackOffWithMaxRetries) backOff).setMaxInterval(10000L);
return errorHandler;
}
@Service
@Transactional
public class PaymentService {
@Autowired
private PaymentRepository paymentRepository;
@Autowired
private ProcessedEventRepository eventRepository;
@KafkaListener(topics = "payment-requested")
public void processPayment(@Payload PaymentRequestEvent event) {
String eventId = [Link]();
try {
// Process payment
Payment payment = [Link]()
.orderId([Link]())
.amount([Link]())
.status([Link])
.build();
[Link](payment);
// Mark as processed
ProcessedEvent processedEvent = [Link]()
.eventId(eventId)
.eventType("PaymentRequested")
.processedAt([Link]())
.build();
[Link](processedEvent);
} catch (Exception e) {
[Link]("Failed to process payment for event: {}", eventId, e);
throw e;
}
}
@Entity
@Table(
name = "processed_events",
indexes = @Index(name = "idx_event_id", columnList = "event_id")
)
public class ProcessedEvent {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
@Service
public class PaymentService {
@KafkaListener(topics = "payment-requested")
public void processPayment(@Payload PaymentRequestEvent event) {
try {
Payment payment = [Link]()
.orderId([Link]())
.amount([Link]())
.status([Link])
.build();
[Link](payment);
} catch (DataIntegrityViolationException e) {
// Duplicate detected, already processed
[Link]("Payment for order {} already exists", [Link]());
}
}
Configuration:
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus,env,beans,mappings
endpoint:
health:
show-details: always
probes:
enabled: true
metrics:
export:
prometheus:
enabled: true
distribution:
percentiles-histogram:
[Link]: true
tracing:
sampling:
probability: 1.0
@Autowired
private ExternalService externalService;
@Override
public Health health() {
try {
boolean isHealthy = [Link]();
if (isHealthy) {
return [Link]()
.withDetail("external-service", "available")
.withDetail("response-time", "45ms")
.build();
} else {
return [Link]()
.withDetail("external-service", "unavailable")
.withDetail("error", "Connection timeout")
.build();
}
} catch (Exception e) {
return [Link]()
.withDetail("external-service", "error")
.withException(e)
.build();
}
}
Custom Metrics:
@Service
public class OrderService {
[Link] = [Link]("[Link]")
.description("Time taken to process an order")
.register(meterRegistry);
}
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> [Link]()
.commonTags("application", "order-service")
.commonTags("environment", "production");
}
@Component
@Endpoint(id = "custom")
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> customInfo() {
Map<String, Object> info = new HashMap<>();
[Link]("application", "order-service");
[Link]("version", "1.0.0");
[Link]("uptime", getUptime());
[Link]("activeOrders", getActiveOrderCount());
return info;
}
@ReadOperation
public String getStatistics(@Selector String name) {
if ("orders".equals(name)) {
return getOrderStatistics();
} else if ("users".equals(name)) {
return getUserStatistics();
}
return "Unknown statistic: " + name;
}
@WriteOperation
public void refreshCache() {
[Link]()
.forEach(name -> [Link](name).clear());
}
@DeleteOperation
public void clearMetrics(@Selector String metricName) {
[Link]([Link](metricName).meters().get(0).getId(
));
}
Web-specific Endpoint:
@Component
@WebEndpoint(id = "orders")
public class OrdersEndpoint {
@Autowired
private OrderService orderService;
@ReadOperation
public ResponseEntity<List<Order>> getRecentOrders(
@Nullable @Selector String status) {
List<Order> orders;
if (status != null) {
orders = [Link](status);
} else {
orders = [Link](10);
}
return [Link](orders);
}
}
@Mock
private UserRepository userRepository;
@Mock
private PasswordEncoder passwordEncoder;
@InjectMocks
private UserService userService;
@Test
void shouldCreateUser() {
// Given
UserRequest request = new UserRequest("john", "password");
User user = new User(1L, "john", "encoded");
when([Link]("password")).thenReturn("encoded");
when([Link](any([Link]))).thenReturn(user);
// When
User result = [Link](request);
// Then
assertThat([Link]()).isEqualTo("john");
verify(userRepository).save(any([Link]));
verify(passwordEncoder).encode("password");
}
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private UserRepository userRepository;
@Test
void shouldCreateUser() throws Exception {
UserRequest request = new UserRequest("john", "password");
[Link](post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content([Link](request)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.username").value("john"))
.andExpect(jsonPath("$.id").exists());
assertThat([Link]("john")).isPresent();
}
@Autowired
private UserRepository userRepository;
@Autowired
private TestEntityManager entityManager;
@Test
void shouldFindUserByUsername() {
// Given
User user = new User("john", "password");
[Link](user);
[Link]();
// When
Optional<User> found = [Link]("john");
// Then
assertThat(found).isPresent();
assertThat([Link]().getUsername()).isEqualTo("john");
}
@Test
void shouldFindUsersByStatus() {
// Given
User active1 = new User("user1", "pass1", [Link]);
User active2 = new User("user2", "pass2", [Link]);
User inactive = new User("user3", "pass3", [Link]);
[Link](active1);
[Link](active2);
[Link](inactive);
[Link]();
// When
List<User> activeUsers = [Link]([Link]);
// Then
assertThat(activeUsers).hasSize(2);
assertThat(activeUsers).extracting(User::getStatus)
.containsOnly([Link]);
}
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Autowired
private ObjectMapper objectMapper;
@Test
@WithMockUser(username = "admin", roles = "ADMIN")
void shouldGetUserById() throws Exception {
User user = new User(1L, "john", "john@[Link]");
when([Link](1L)).thenReturn(user);
[Link](get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.username").value("john"));
}
@Container
static PostgreSQLContainer<?> postgres = new
PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@Container
static KafkaContainer kafka = new KafkaContainer(
[Link]("confluentinc/cp-kafka:7.4.0"));
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
[Link]("[Link]", postgres::getJdbcUrl);
[Link]("[Link]", postgres::getUsername);
[Link]("[Link]", postgres::getPassword);
[Link]("[Link]-servers", kafka::getBootstrapServers);
}
@Autowired
private OrderService orderService;
@Test
void shouldCreateOrderWithRealDatabaseAndKafka() {
OrderRequest request = new OrderRequest(/* ... */);
Order order = [Link](request);
assertThat([Link]()).isNotNull();
assertThat([Link]()).isEqualTo([Link]);
}
Build stage
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /app
COPY [Link] .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests
Runtime stage
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar [Link]
EXPOSE 8080
[Link]:
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/myapp
- SPRING_REDIS_HOST=redis
depends_on:
- db
- redis
networks:
- app-network
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- app-network
redis:
image: redis:7-alpine
networks:
- app-network
volumes:
postgres-data:
networks:
app-network:
driver: bridge
2. Kubernetes Deployment:
[Link]:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
labels:
app: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: myregistry/order-
service:1.0.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: SPRING_DATASOURCE_URL
valueFrom:
secretKeyRef:
name: db-secrets
key: url
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
3. CI/CD Pipeline (GitHub Actions):
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
build:
needs: test
runs-on: ubuntu-latest
if: [Link] == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
Blue-Green Deployment:
protocol: TCP
port: 80
targetPort: 8080
Canary Deployment:
Stable version (90% traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service-stable
spec:
replicas: 9
selector:
matchLabels:
app: order-service
track: stable
template:
metadata:
labels:
app: order-service
track: stable
version: "1.0.0"
spec:
containers:
- name: order-service
image: myregistry/order-service:1.0.0
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service # Matches both stable and canary
ports:
protocol: TCP
port: 80
targetPort: 8080
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
@Autowired
private PaymentService paymentService;
@Autowired
private InventoryService inventoryService;
3. Factory Pattern:
public interface PaymentProcessor {
Payment process(PaymentRequest request);
}
@Component
public class CreditCardProcessor implements PaymentProcessor {
public Payment process(PaymentRequest request) {
// Credit card logic
}
}
@Component
public class PayPalProcessor implements PaymentProcessor {
public Payment process(PaymentRequest request) {
// PayPal logic
}
}
@Component
public class PaymentProcessorFactory {
@Autowired
private Map<String, PaymentProcessor> processors;
}
4. Strategy Pattern:
public interface PricingStrategy {
BigDecimal calculatePrice(Order order);
}
@Component("regularPricing")
public class RegularPricingStrategy implements PricingStrategy {
public BigDecimal calculatePrice(Order order) {
return [Link]().stream()
.map(Item::getPrice)
.reduce([Link], BigDecimal::add);
}
}
@Component("premiumPricing")
public class PremiumPricingStrategy implements PricingStrategy {
public BigDecimal calculatePrice(Order order) {
BigDecimal total = [Link]().stream()
.map(Item::getPrice)
.reduce([Link], BigDecimal::add);
return [Link](new BigDecimal("0.9")); // 10% discount
}
}
@Service
public class OrderService {
@Autowired
@Qualifier("regularPricing")
private PricingStrategy pricingStrategy;
5. Builder Pattern:
@Builder
@Data
public class OrderRequest {
private Long userId;
private List<OrderItem> items;
private Address shippingAddress;
private PaymentMethod paymentMethod;
// Usage
OrderRequest request = [Link]()
.userId(1L)
.items(items)
.defaultShipping()
.paymentMethod(PaymentMethod.CREDIT_CARD)
.build();
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Component
public class OrderEventListener {
@EventListener
@Async
public void handleOrderCreated(OrderCreatedEvent event) {
Order order = [Link]();
// Send notification, update analytics, etc.
}
Architecture Design:
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping
@ResponseStatus([Link])
public OrderResponse createOrder(@RequestBody @Valid OrderRequest
request) {
// Synchronous validation only
String orderId = [Link](request);
@Service
public class OrderService {
@Autowired
private KafkaTemplate<String, OrderEvent> kafkaTemplate;
@Autowired
private RedisTemplate<String, OrderStatus> redisTemplate;
return orderId;
}
@Component
public class OrderProcessor {
@KafkaListener(
topics = "order-submitted",
concurrency = "10" // Process 10 messages in parallel
)
@Transactional
public void processOrder(@Payload OrderEvent event) {
String orderId = [Link]();
try {
// Process order with all business logic
validateInventory(event);
processPayment(event);
reserveItems(event);
updateOrderStatus(orderId, [Link]);
} catch (PaymentException e) {
updateOrderStatus(orderId, OrderStatus.PAYMENT_FAILED);
publishToDeadLetterQueue(event, e);
} catch (Exception e) {
updateOrderStatus(orderId, [Link]);
throw e; // Trigger retry
}
}
Performance Optimizations:
Via Actuator
curl -X GET [Link] -o [Link]
Via JVM
jmap -dump:live,format=b,file=[Link] <PID>
5. JVM Tuning:
Enable GC logging
-Xlog:gc*:file=[Link]:time,uptime,level,tags
Use appropriate GC
-XX:+UseG1GC
@Configuration
public class RateLimitConfig {
@Bean
public Bucket bucket() {
Bandwidth limit = [Link](100, [Link](100,
[Link](1)));
return [Link]()
.addLimit(limit)
.build();
}
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
@Autowired
private CacheManager cacheManager;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if ([Link](1)) {
return true;
} else {
[Link](HttpStatus.TOO_MANY_REQUESTS.value());
[Link]().write("Rate limit exceeded");
return false;
}
}
if (bucket == null) {
Bandwidth limit = [Link](
100,
[Link](100, [Link](1))
);
bucket = [Link]().addLimit(limit).build();
[Link](clientId, bucket);
}
return bucket;
}
@Component
public class RedisRateLimiter {
@Autowired
private StringRedisTemplate redisTemplate;
return false;
}
@RestController
public class ApiController {
@Autowired
private RedisRateLimiter rateLimiter;
@GetMapping("/api/resource")
public ResponseEntity<?> getResource(HttpServletRequest request) {
String clientId = getClientId(request);
return [Link]([Link]());
}
spring:
cloud:
gateway:
routes:
- id: order_service
uri: [Link]
predicates:
- Path=/api/orders/**
filters:
- name: RequestRateLimiter
args:
[Link]: 10
[Link]: 20
[Link]: 1
key-resolver: "#{@userKeyResolver}"
@Configuration
public class GatewayConfig {
@Bean
public KeyResolver userKeyResolver() {
return exchange -> {
String userId = [Link]()
.getHeaders()
.getFirst("X-User-Id");
return [Link](userId != null ? userId : "anonymous");
};
}
Database-per-Tenant Approach:
@Configuration
public class MultiTenantConfig {
@Bean
public DataSource dataSource() {
return new TenantRoutingDataSource();
}
@Override
protected Object determineCurrentLookupKey() {
return [Link]();
}
@Component
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String tenantId = [Link]("X-Tenant-ID");
if (tenantId != null) {
[Link](tenantId);
} else {
[Link](HttpStatus.BAD_REQUEST.value());
return false;
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
[Link]();
}
Schema-per-Tenant Approach:
@Entity
@Table(name = "users")
@[Link]
public class User {
@Id
private Long id;
// Hibernate automatically filters by tenant
private String username;
@Configuration
public class HibernateConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em =
new LocalContainerEntityManagerFactoryBean();
// Configure multi-tenancy
Map<String, Object> properties = new HashMap<>();
[Link]("[Link]", "SCHEMA");
[Link]("hibernate.tenant_identifier_resolver",
tenantIdentifierResolver());
[Link]("hibernate.multi_tenant_connection_provider",
multiTenantConnectionProvider());
[Link](properties);
return em;
}
References
[1] InterviewBit. (2026). Top 40+ Spring Boot Interview Questions & Answers.
[Link]
[2] We Create Problems. (2026). 100+ Spring Boot Interview Questions and
Answers. [Link]
interview-questions
[11] GUVI. (2025). Spring Boot 3.x Interview Prep: Latest 50 Common
Questions. [Link]
[13] Hirist. (2026). Top 25+ Spring Security Interview Questions and Answers.
[Link]
answers/
[14] Java Bulletin. (2026). Spring Boot Interview Question – Improve API
Latency. [Link]
improve