BLOG POSTS
Spring Interview Questions and Answers

Spring Interview Questions and Answers

Spring Framework interviews can be intimidating, especially when you’re dealing with complex topics like dependency injection, AOP, and Spring Boot configurations. Whether you’re a seasoned developer looking to brush up on fundamentals or a system administrator working with Spring-based applications, understanding these core concepts is crucial for both landing that dream job and effectively managing Spring applications in production environments. This comprehensive guide covers the most frequently asked Spring interview questions, from basic IoC container concepts to advanced topics like microservices architecture, complete with practical examples and real-world scenarios you’ll actually encounter in your daily work.

Core Spring Framework Concepts

Let’s start with the fundamental questions that almost every Spring interview will cover. These aren’t just theoretical concepts – they’re the building blocks you’ll use every day.

Q: What is Inversion of Control (IoC) and how does Spring implement it?

IoC is a design principle where the control of object creation and dependency management is transferred from the application code to an external container. Spring implements IoC through its ApplicationContext and BeanFactory containers.

@Component
public class OrderService {
    private final PaymentService paymentService;
    private final InventoryService inventoryService;
    
    // Constructor injection - Spring handles dependency creation
    public OrderService(PaymentService paymentService, 
                       InventoryService inventoryService) {
        this.paymentService = paymentService;
        this.inventoryService = inventoryService;
    }
    
    public void processOrder(Order order) {
        inventoryService.reserveItems(order.getItems());
        paymentService.processPayment(order.getTotal());
    }
}

Q: Explain the different types of dependency injection in Spring.

Spring supports three main types of dependency injection:

  • Constructor Injection: Dependencies are provided through class constructors (recommended approach)
  • Setter Injection: Dependencies are provided through setter methods
  • Field Injection: Dependencies are injected directly into fields using @Autowired
// Constructor Injection (Recommended)
@Service
public class UserService {
    private final UserRepository userRepository;
    
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

// Setter Injection
@Service
public class EmailService {
    private NotificationService notificationService;
    
    @Autowired
    public void setNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
}

// Field Injection (Not recommended for production)
@Service
public class ReportService {
    @Autowired
    private DataService dataService;
}

Bean Lifecycle and Scopes

Q: Describe the Spring Bean lifecycle.

Understanding the bean lifecycle is crucial for implementing initialization and cleanup logic properly. Here’s the complete lifecycle with practical examples:

@Component
public class DatabaseConnection implements InitializingBean, DisposableBean {
    
    private Connection connection;
    
    @PostConstruct
    public void initConnection() {
        System.out.println("@PostConstruct: Initializing database connection");
        // Initialize connection pool
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: After properties set");
        // Additional initialization after all properties are set
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("@PreDestroy: Cleaning up resources");
        // Close connections, release resources
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean: Destroy method called");
        // Final cleanup operations
    }
}

Q: What are the different bean scopes in Spring?

Scope Description Use Case Thread Safe
singleton One instance per Spring container Stateless services, repositories Must be designed thread-safe
prototype New instance for each request Stateful objects, temporary objects Each instance is separate
request One instance per HTTP request Web-specific data holders Request-scoped
session One instance per HTTP session User session data Session-scoped
application One instance per ServletContext Application-wide shared data Must be thread-safe
@Component
@Scope("prototype")
public class ShoppingCart {
    private List<Item> items = new ArrayList<>();
    
    public void addItem(Item item) {
        items.add(item);
    }
}

@Controller
@Scope(value = WebApplicationContext.SCOPE_SESSION, 
       proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
    private String userId;
    private LocalDateTime loginTime;
    
    public void initSession(String userId) {
        this.userId = userId;
        this.loginTime = LocalDateTime.now();
    }
}

Spring Boot Configuration and Auto-Configuration

Q: How does Spring Boot auto-configuration work?

Spring Boot’s auto-configuration is one of its most powerful features, automatically configuring beans based on classpath dependencies and existing configurations. Here’s how it works under the hood:

// Custom auto-configuration example
@Configuration
@ConditionalOnClass(RedisTemplate.class)
@ConditionalOnProperty(name = "app.redis.enabled", havingValue = "true")
@EnableConfigurationProperties(RedisProperties.class)
public class CustomRedisAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

// Enable auto-configuration in META-INF/spring.factories
// org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
// com.example.config.CustomRedisAutoConfiguration

Q: How do you create custom configuration properties?

// Configuration properties class
@ConfigurationProperties(prefix = "app.database")
@Data
public class DatabaseProperties {
    private String url;
    private String username;
    private String password;
    private Pool pool = new Pool();
    
    @Data
    public static class Pool {
        private int maxSize = 10;
        private int minSize = 5;
        private Duration maxWait = Duration.ofSeconds(30);
    }
}

// Configuration class
@Configuration
@EnableConfigurationProperties(DatabaseProperties.class)
public class DatabaseConfig {
    
    @Bean
    public DataSource customDataSource(DatabaseProperties properties) {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(properties.getUrl());
        config.setUsername(properties.getUsername());
        config.setPassword(properties.getPassword());
        config.setMaximumPoolSize(properties.getPool().getMaxSize());
        config.setMinimumIdle(properties.getPool().getMinSize());
        return new HikariDataSource(config);
    }
}

Corresponding application.yml:

app:
  database:
    url: jdbc:postgresql://localhost:5432/mydb
    username: ${DB_USER:admin}
    password: ${DB_PASSWORD:secret}
    pool:
      max-size: 20
      min-size: 5
      max-wait: PT45S

Spring Data and JPA Integration

Q: How do you implement custom repository methods in Spring Data JPA?

This is a common real-world scenario where you need to go beyond basic CRUD operations:

// Custom repository interface
public interface CustomUserRepository {
    List<User> findActiveUsersByDepartment(String department);
    Page<User> findUsersWithComplexCriteria(UserSearchCriteria criteria, Pageable pageable);
}

// Custom repository implementation
@Repository
public class CustomUserRepositoryImpl implements CustomUserRepository {
    
    @PersistenceContext
    private EntityManager entityManager;
    
    @Override
    public List<User> findActiveUsersByDepartment(String department) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);
        Root<User> user = query.from(User.class);
        
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(cb.equal(user.get("department"), department));
        predicates.add(cb.equal(user.get("active"), true));
        
        query.where(predicates.toArray(new Predicate[0]));
        return entityManager.createQuery(query).getResultList();
    }
    
    @Override
    public Page<User> findUsersWithComplexCriteria(UserSearchCriteria criteria, 
                                                   Pageable pageable) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);
        Root<User> user = query.from(User.class);
        
        List<Predicate> predicates = buildPredicates(cb, user, criteria);
        query.where(predicates.toArray(new Predicate[0]));
        
        TypedQuery<User> typedQuery = entityManager.createQuery(query);
        typedQuery.setFirstResult((int) pageable.getOffset());
        typedQuery.setMaxResults(pageable.getPageSize());
        
        List<User> results = typedQuery.getResultList();
        long total = getTotalCount(criteria);
        
        return new PageImpl<>(results, pageable, total);
    }
}

// Main repository interface extending both JpaRepository and custom interface
public interface UserRepository extends JpaRepository<User, Long>, CustomUserRepository {
    
    @Query("SELECT u FROM User u WHERE u.email = ?1 AND u.active = true")
    Optional<User> findActiveUserByEmail(String email);
    
    @Modifying
    @Query("UPDATE User u SET u.lastLoginDate = :loginDate WHERE u.id = :userId")
    int updateLastLoginDate(@Param("userId") Long userId, 
                           @Param("loginDate") LocalDateTime loginDate);
}

Aspect-Oriented Programming (AOP)

Q: Implement a logging aspect that captures method execution time and parameters.

AOP is essential for cross-cutting concerns like logging, security, and transaction management:

@Aspect
@Component
@Slf4j
public class LoggingAspect {
    
    @Pointcut("@annotation(com.example.annotation.Loggable)")
    public void loggableMethods() {}
    
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    @Around("loggableMethods() || serviceMethods()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        // Log method entry with parameters
        Object[] args = joinPoint.getArgs();
        log.info("Entering method: {}.{} with arguments: {}", 
                className, methodName, Arrays.toString(args));
        
        long startTime = System.currentTimeMillis();
        Object result = null;
        
        try {
            result = joinPoint.proceed();
            long executionTime = System.currentTimeMillis() - startTime;
            
            log.info("Method: {}.{} executed successfully in {} ms", 
                    className, methodName, executionTime);
            
            return result;
        } catch (Exception e) {
            long executionTime = System.currentTimeMillis() - startTime;
            log.error("Method: {}.{} failed after {} ms with exception: {}", 
                     className, methodName, executionTime, e.getMessage());
            throw e;
        }
    }
    
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "exception")
    public void logException(JoinPoint joinPoint, Throwable exception) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        log.error("Exception in method: {}.{} - {}", 
                 className, methodName, exception.getMessage(), exception);
    }
}

// Custom annotation for selective logging
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
    boolean logParams() default true;
    boolean logResult() default false;
}

// Usage example
@Service
public class OrderService {
    
    @Loggable(logParams = true, logResult = true)
    public Order processOrder(OrderRequest request) {
        // Business logic here
        return new Order(request);
    }
    
    public void sendNotification(String email) {
        // This will be logged due to serviceMethods() pointcut
    }
}

Spring Security Implementation

Q: How do you implement JWT-based authentication in Spring Security?

Here’s a complete JWT implementation that you’ll commonly encounter in microservices architectures:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    
    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    
    @Autowired
    private JwtRequestFilter jwtRequestFilter;
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    public AuthenticationManager authenticationManager(
            AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers(HttpMethod.GET, "/api/products/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        
        return http.build();
    }
}

@Component
public class JwtRequestFilter extends OncePerRequestFilter {
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                  HttpServletResponse response, 
                                  FilterChain chain) throws ServletException, IOException {
        
        final String requestTokenHeader = request.getHeader("Authorization");
        
        String username = null;
        String jwtToken = null;
        
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtUtil.getUsernameFromToken(jwtToken);
            } catch (IllegalArgumentException e) {
                logger.error("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                logger.error("JWT Token has expired");
            }
        }
        
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            
            if (jwtUtil.validateToken(jwtToken, userDetails)) {
                UsernamePasswordAuthenticationToken authToken = 
                    new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        chain.doFilter(request, response);
    }
}

Microservices and Spring Cloud

Q: How do you implement service discovery and load balancing with Spring Cloud?

Modern Spring applications often run in distributed environments where service discovery is crucial:

// Eureka Server Configuration
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

// Eureka Server application.yml
server:
  port: 8761
  
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

// Client Service Configuration
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

// Feign Client for inter-service communication
@FeignClient(name = "inventory-service", fallback = InventoryServiceFallback.class)
public interface InventoryServiceClient {
    
    @GetMapping("/api/inventory/check/{productId}")
    InventoryResponse checkInventory(@PathVariable("productId") Long productId);
    
    @PostMapping("/api/inventory/reserve")
    ReservationResponse reserveItems(@RequestBody ReservationRequest request);
}

// Fallback implementation for circuit breaker
@Component
public class InventoryServiceFallback implements InventoryServiceClient {
    
    @Override
    public InventoryResponse checkInventory(Long productId) {
        return InventoryResponse.builder()
            .productId(productId)
            .available(false)
            .message("Inventory service is currently unavailable")
            .build();
    }
    
    @Override
    public ReservationResponse reserveItems(ReservationRequest request) {
        return ReservationResponse.builder()
            .success(false)
            .message("Unable to reserve items - service unavailable")
            .build();
    }
}

// Circuit Breaker with Resilience4j
@RestController
@RequiredArgsConstructor
public class OrderController {
    
    private final InventoryServiceClient inventoryClient;
    
    @PostMapping("/api/orders")
    @CircuitBreaker(name = "inventory-service", fallbackMethod = "fallbackCreateOrder")
    @TimeLimiter(name = "inventory-service")
    @Retry(name = "inventory-service")
    public CompletableFuture<ResponseEntity<OrderResponse>> createOrder(
            @RequestBody OrderRequest request) {
        
        return CompletableFuture.supplyAsync(() -> {
            InventoryResponse inventory = inventoryClient.checkInventory(request.getProductId());
            
            if (inventory.isAvailable()) {
                // Process order logic
                OrderResponse response = processOrder(request);
                return ResponseEntity.ok(response);
            } else {
                return ResponseEntity.badRequest()
                    .body(OrderResponse.error("Product not available"));
            }
        });
    }
    
    public CompletableFuture<ResponseEntity<OrderResponse>> fallbackCreateOrder(
            OrderRequest request, Exception ex) {
        return CompletableFuture.completedFuture(
            ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
                .body(OrderResponse.error("Service temporarily unavailable"))
        );
    }
}

Testing Strategies

Q: How do you write effective integration tests for Spring applications?

Testing is crucial for maintaining reliable Spring applications, especially in production environments:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Testcontainers
class OrderServiceIntegrationTest {
    
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:14")
            .withDatabaseName("testdb")
            .withUsername("test")
            .withPassword("test");
    
    @Container
    static GenericContainer<?> redis = new GenericContainer<>("redis:7-alpine")
            .withExposedPorts(6379);
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Autowired
    private OrderRepository orderRepository;
    
    @MockBean
    private PaymentService paymentService;
    
    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
        registry.add("spring.redis.host", redis::getHost);
        registry.add("spring.redis.port", redis::getFirstMappedPort);
    }
    
    @Test
    @Transactional
    @Rollback
    void shouldCreateOrderSuccessfully() {
        // Given
        OrderRequest request = OrderRequest.builder()
            .customerId(1L)
            .productId(100L)
            .quantity(2)
            .build();
        
        when(paymentService.processPayment(any())).thenReturn(
            PaymentResponse.success("payment-123")
        );
        
        // When
        ResponseEntity<OrderResponse> response = restTemplate.postForEntity(
            "/api/orders", request, OrderResponse.class
        );
        
        // Then
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
        assertThat(response.getBody().getOrderId()).isNotNull();
        
        Optional<Order> savedOrder = orderRepository.findById(response.getBody().getOrderId());
        assertThat(savedOrder).isPresent();
        assertThat(savedOrder.get().getStatus()).isEqualTo(OrderStatus.CONFIRMED);
    }
    
    @Test
    void shouldHandlePaymentFailureGracefully() {
        // Given
        OrderRequest request = OrderRequest.builder()
            .customerId(1L)
            .productId(100L)
            .quantity(2)
            .build();
        
        when(paymentService.processPayment(any())).thenThrow(
            new PaymentException("Insufficient funds")
        );
        
        // When
        ResponseEntity<OrderResponse> response = restTemplate.postForEntity(
            "/api/orders", request, OrderResponse.class
        );
        
        // Then
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
        assertThat(response.getBody().getError()).contains("Payment failed");
    }
}

// Unit test with Spring Test Context
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {OrderService.class})
@MockBean({PaymentService.class, InventoryService.class, OrderRepository.class})
class OrderServiceTest {
    
    @Autowired
    private OrderService orderService;
    
    @MockBean
    private PaymentService paymentService;
    
    @MockBean
    private InventoryService inventoryService;
    
    @MockBean
    private OrderRepository orderRepository;
    
    @Test
    void shouldProcessOrderWithValidInventory() {
        // Given
        Order order = createTestOrder();
        when(inventoryService.checkAvailability(anyLong(), anyInt())).thenReturn(true);
        when(paymentService.processPayment(any())).thenReturn(PaymentResponse.success("123"));
        when(orderRepository.save(any())).thenReturn(order);
        
        // When
        OrderResponse result = orderService.processOrder(createOrderRequest());
        
        // Then
        assertThat(result.getOrderId()).isEqualTo(order.getId());
        verify(inventoryService).reserveItems(order.getProductId(), order.getQuantity());
        verify(paymentService).processPayment(any());
    }
}

Performance Optimization and Best Practices

Q: How do you optimize Spring Boot application performance?

Performance optimization is critical for production deployments, especially when running on VPS or dedicated servers:

  • Database Connection Pooling: Configure HikariCP properly for your workload
  • Caching Strategy: Implement multi-level caching with Redis and Spring Cache
  • JVM Tuning: Optimize garbage collection and memory settings
  • Lazy Loading: Use @Lazy annotations and lazy initialization
  • Async Processing: Implement asynchronous methods for heavy operations
// Database optimization configuration
@Configuration
public class DatabaseOptimizationConfig {
    
    @Bean
    @ConfigurationProperties("app.datasource.hikari")
    public HikariConfig hikariConfig() {
        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);
        config.setLeakDetectionThreshold(60000);
        return config;
    }
    
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource(hikariConfig());
    }
}

// Caching configuration
@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofHours(1))
            .serializeKeysWith(RedisSerializationContext.SerializationPair
                .fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair
                .fromSerializer(new GenericJackson2JsonRedisSerializer()));
        
        return RedisCacheManager.builder(connectionFactory)
            .cacheDefaults(config)
            .build();
    }
}

// Service with optimized caching and async processing
@Service
@Slf4j
public class ProductService {
    
    @Cacheable(value = "products", key = "#productId")
    public Product getProduct(Long productId) {
        log.info("Fetching product from database: {}", productId);
        return productRepository.findById(productId)
            .orElseThrow(() -> new ProductNotFoundException(productId));
    }
    
    @CacheEvict(value = "products", key = "#product.id")
    public Product updateProduct(Product product) {
        return productRepository.save(product);
    }
    
    @Async("taskExecutor")
    @EventListener
    public CompletableFuture<Void> handleProductUpdated(ProductUpdatedEvent event) {
        log.info("Processing product update asynchronously: {}", event.getProductId());
        
        // Heavy processing like updating search indexes, sending notifications
        updateSearchIndex(event.getProductId());
        sendNotifications(event);
        
        return CompletableFuture.completedFuture(null);
    }
}

// Async configuration
@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean("taskExecutor")
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(16);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-task-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

Common Pitfalls and Troubleshooting

Q: What are the most common Spring Boot issues and how do you debug them?

Here are the issues you’ll encounter most frequently in production environments:

Issue Symptoms Solution Prevention
Circular Dependencies BeanCurrentlyInCreationException Use @Lazy, refactor design Proper dependency design
N+1 Query Problem Poor performance, many SQL queries Use @EntityGraph, JOIN FETCH Query optimization reviews
Memory Leaks OutOfMemoryError, increasing heap usage Profile with JProfiler, fix resource leaks Proper resource management
Transaction Issues Data inconsistency, rollback failures Proper @Transactional usage Transaction boundary design
// Common debugging configuration
@Configuration
public class DebuggingConfig {
    
    // Enable SQL logging for development
    @Bean
    @Profile("dev")
    public Logger sqlLogger() {
        Logger logger = (Logger) LoggerFactory.getLogger("org.hibernate.SQL");
        logger.setLevel(Level.DEBUG);
        return logger;
    }
    
    // Health check endpoint
    @Component
    public class CustomHealthIndicator implements HealthIndicator {
        
        @Autowired
        private DataSource dataSource;
        
        @Override
        public Health health() {
            try (Connection connection = dataSource.getConnection()) {
                if (connection.isValid(1000)) {
                    return Health.up()
                        .withDetail("database", "Available")
                        .withDetail("connection_pool", getPoolStatus())
                        .build();
                }
            } catch (SQLException e) {
                return Health.down()
                    .withDetail("database", "Unavailable")
                    .withException(e)
                    .build();
            }
            return Health.down().withDetail("database", "Unknown").build();
        }
    }
}

// Debugging utilities
@RestController
@Profile({"dev", "staging"})
public class DebugController {
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @GetMapping("/debug/beans")
    public Map<String, Object> getBeans() {
        return Arrays.stream(applicationContext.getBeanDefinitionNames())
            .collect(Collectors.toMap(
                name -> name,
                name -> applicationContext.getBean(name).getClass().getSimpleName()
            ));
    }
    
    @GetMapping("/debug/memory")
    public Map<String, Long> getMemoryInfo() {
        Runtime runtime = Runtime.getRuntime();
        Map<String, Long> memoryInfo = new HashMap<>();
        memoryInfo.put("totalMemory", runtime.totalMemory());
        memoryInfo.put("freeMemory", runtime.freeMemory());
        memoryInfo.put("usedMemory", runtime.totalMemory() - runtime.freeMemory());
        memoryInfo.put("maxMemory", runtime.maxMemory());
        return memoryInfo;
    }
}

Understanding these Spring concepts thoroughly will not only help you ace interviews but also build robust, scalable applications in production. Remember that interviewers often ask follow-up questions about real-world scenarios, so always be prepared to explain how you’ve used these concepts in actual projects. Practice implementing these examples in your development environment, and don’t forget to check the official Spring Guides for the latest best practices and updates.

The key to succeeding in Spring interviews is combining theoretical knowledge with practical experience. Focus on understanding the underlying principles, practice with real code examples, and be ready to discuss performance implications and production considerations. Whether you’re deploying on cloud platforms or managing your own infrastructure, these concepts form the foundation of professional Spring development.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked