Spring Common Questions¶
Spring Core¶
Q1: What is Inversion of Control (IoC)?¶
IoC is a design principle where object creation and lifecycle management is delegated to a container instead of being controlled by application code.
// Without IoC - Application controls
public class OrderService {
private PaymentService payment = new StripePaymentService(); // Tight coupling
}
// With IoC - Container controls
@Service
public class OrderService {
private final PaymentService payment; // Injected by container
public OrderService(PaymentService payment) {
this.payment = payment;
}
}
Benefits: Loose coupling, testability, flexibility, single responsibility.
Q2: Constructor vs Setter vs Field Injection?¶
// Constructor (RECOMMENDED)
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
// Setter (for optional dependencies)
@Service
public class NotificationService {
private SmsService smsService;
@Autowired(required = false)
public void setSmsService(SmsService smsService) {
this.smsService = smsService;
}
}
// Field (AVOID)
@Service
public class UserService {
@Autowired
private UserRepository repository; // Hard to test!
}
| Aspect | Constructor | Setter | Field |
|---|---|---|---|
| Immutability | Yes (final) | No | No |
| Testability | Easy | Medium | Hard |
| Optional deps | No | Yes | Yes |
| Circular deps | Fails fast | Allows | Allows |
Q3: What are Bean Scopes?¶
@Component
@Scope("singleton") // Default - one per container
@Scope("prototype") // New instance each request
@Scope("request") // One per HTTP request
@Scope("session") // One per HTTP session
Prototype in Singleton Problem:
@Service // Singleton
public class OrderService {
@Autowired
private ShoppingCart cart; // Prototype - WRONG! Same instance always
// Solution: Use ObjectFactory
@Autowired
private ObjectFactory<ShoppingCart> cartFactory;
public void checkout() {
ShoppingCart cart = cartFactory.getObject(); // New instance
}
}
Q4: @Component vs @Bean?¶
// @Component - Class-level, auto-detected via component scanning
@Component
public class MyService { }
// @Bean - Method-level in @Configuration, for third-party classes
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Q5: Bean Lifecycle Callbacks?¶
@Service
public class CacheService {
@PostConstruct // After dependency injection
public void init() {
loadCache();
}
@PreDestroy // Before destruction
public void cleanup() {
persistCache();
}
}
Order: Constructor → DI → @PostConstruct → afterPropertiesSet → init-method
Spring Boot¶
Q6: What is @SpringBootApplication?¶
Combines three annotations:
@SpringBootApplication // Equivalent to:
@Configuration // Configuration class
@EnableAutoConfiguration // Enable auto-configuration
@ComponentScan // Scan current package + subpackages
public class Application { }
Q7: How does Auto-Configuration work?¶
@EnableAutoConfigurationtriggers scanning- Reads
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - Each auto-config has
@Conditionalannotations: - Your custom beans take precedence (
@ConditionalOnMissingBean)
Q8: Externalized Configuration Priority?¶
- Command line args (
--server.port=9000) - Java system properties (
-Dserver.port=9000) - OS environment variables (
SERVER_PORT=9000) - Profile-specific properties (
application-prod.yml) - Application properties (
application.yml)
Q9: How to create a Custom Starter?¶
-
Create auto-configuration class:
-
Register in
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports -
Create starter module with dependencies
Spring MVC¶
Q10: Request Processing Flow?¶
Request → DispatcherServlet → HandlerMapping → Interceptor.preHandle
→ Controller → Interceptor.postHandle → ViewResolver → View → Response
Q11: @Controller vs @RestController?¶
@Controller // Returns view name
public class WebController {
@GetMapping("/page")
public String page(Model model) {
return "page"; // View name
}
}
@RestController // @Controller + @ResponseBody
public class ApiController {
@GetMapping("/api/data")
public Data getData() {
return new Data(); // Serialized to JSON
}
}
Q12: Exception Handling?¶
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
return new ErrorResponse("NOT_FOUND", ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
return new ErrorResponse("VALIDATION_ERROR", getErrors(ex));
}
}
Spring Data JPA¶
Q13: JpaRepository vs CrudRepository?¶
| Method | CrudRepository | JpaRepository |
|---|---|---|
| save | ✓ | ✓ |
| findById | ✓ | ✓ |
| findAll | ✓ (Iterable) | ✓ (List) |
| flush | ✗ | ✓ |
| saveAndFlush | ✗ | ✓ |
| deleteInBatch | ✗ | ✓ |
| getReferenceById | ✗ | ✓ |
Q14: N+1 Problem?¶
Problem: Loading parent entities causes N additional queries for children.
List<Order> orders = orderRepository.findAll(); // 1 query
for (Order o : orders) {
o.getItems().size(); // N queries!
}
Solutions:
// 1. JOIN FETCH
@Query("SELECT o FROM Order o JOIN FETCH o.items")
List<Order> findAllWithItems();
// 2. @EntityGraph
@EntityGraph(attributePaths = {"items"})
List<Order> findAll();
// 3. @BatchSize on entity
@OneToMany
@BatchSize(size = 50)
private List<OrderItem> items;
Q15: Lazy vs Eager Loading?¶
@ManyToOne(fetch = FetchType.LAZY) // Load on access (default for collections)
@ManyToOne(fetch = FetchType.EAGER) // Load immediately (default for single)
LazyInitializationException: Accessing lazy-loaded entity outside session. Solution: Keep session open, use JOIN FETCH, or use DTO projection.
Q16: @Transactional Best Practices?¶
@Transactional(
readOnly = true, // Optimize for reads
propagation = REQUIRED, // Use existing or create new
isolation = READ_COMMITTED, // Prevent dirty reads
timeout = 30, // Timeout in seconds
rollbackFor = BusinessException.class // Rollback for checked
)
public void process() { }
Common pitfalls: - Self-invocation bypasses proxy - Checked exceptions don't rollback by default - readOnly doesn't prevent writes (just hints)
Q17: Optimistic vs Pessimistic Locking?¶
// Optimistic - @Version field
@Entity
public class Order {
@Version
private Long version; // Auto-incremented on update
}
// Pessimistic - Database lock
@Lock(LockModeType.PESSIMISTIC_WRITE)
Optional<Order> findById(Long id);
| Aspect | Optimistic | Pessimistic |
|---|---|---|
| Concurrency | High | Low |
| Conflicts | Detect at commit | Prevent |
| Use case | Read-heavy | Write-heavy |
Spring Security¶
Q18: Security Filter Chain?¶
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt())
.build();
}
Q19: JWT vs Session Authentication?¶
| Aspect | JWT | Session |
|---|---|---|
| Storage | Client (token) | Server |
| Scalability | Stateless | Requires sticky sessions |
| Revocation | Difficult | Easy |
| Size | Larger | Cookie ID only |
Q20: @PreAuthorize vs @Secured?¶
// @PreAuthorize - SpEL expressions, more flexible
@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
public User getUser(Long userId) { }
// @Secured - Simple role check
@Secured("ROLE_ADMIN")
public void adminOnly() { }
AOP¶
Q21: What is AOP?¶
Aspect-Oriented Programming modularizes cross-cutting concerns (logging, security, transactions).
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("Entering: {}", joinPoint.getSignature());
Object result = joinPoint.proceed();
log.info("Exiting: {}", joinPoint.getSignature());
return result;
}
}
Terms: Aspect, Join Point, Advice, Pointcut, Weaving
Q22: Spring AOP vs AspectJ?¶
| Aspect | Spring AOP | AspectJ |
|---|---|---|
| Weaving | Runtime (proxy) | Compile/Load time |
| Join points | Method only | Methods, fields, constructors |
| Performance | Slower | Faster |
| Complexity | Simpler | More complex |
| Self-invocation | Not intercepted | Intercepted |
Q23: Self-Invocation Problem?¶
@Service
public class OrderService {
@Transactional
public void processOrder() {
validateOrder(); // NOT transactional! Direct call
}
@Transactional(propagation = REQUIRES_NEW)
public void validateOrder() { }
}
Solutions:
1. Inject self: @Autowired private OrderService self;
2. Use AopContext.currentProxy()
3. Extract to separate service
Testing¶
Q24: @SpringBootTest vs @WebMvcTest?¶
// Full application context
@SpringBootTest(webEnvironment = RANDOM_PORT)
class IntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
}
// Web layer only
@WebMvcTest(UserController.class)
class ControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
}
// Repository layer only
@DataJpaTest
class RepositoryTest {
@Autowired
private UserRepository repository;
}
Q25: How to test secured endpoints?¶
@WebMvcTest(OrderController.class)
class SecuredControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(roles = "ADMIN")
void adminCanAccess() throws Exception {
mockMvc.perform(get("/admin/orders"))
.andExpect(status().isOk());
}
@Test
void unauthenticatedDenied() throws Exception {
mockMvc.perform(get("/admin/orders"))
.andExpect(status().isUnauthorized());
}
}
Performance & Best Practices¶
Q26: How to improve Spring Boot startup time?¶
- Use lazy initialization:
spring.main.lazy-initialization=true - Exclude unused auto-configurations
- Use Spring AOT (Ahead-of-Time compilation)
- Profile startup:
spring.application.admin.enabled=true - Use GraalVM native image
Q27: Connection Pool Configuration?¶
spring:
datasource:
hikari:
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 300000
pool-name: HikariPool
max-lifetime: 1800000
connection-timeout: 20000
Q28: Caching Strategies?¶
@EnableCaching
@Configuration
public class CacheConfig { }
@Service
public class ProductService {
@Cacheable(value = "products", key = "#id")
public Product findById(Long id) { }
@CachePut(value = "products", key = "#product.id")
public Product update(Product product) { }
@CacheEvict(value = "products", key = "#id")
public void delete(Long id) { }
@CacheEvict(value = "products", allEntries = true)
public void clearCache() { }
}
Design Decisions¶
Q29: When to use Spring WebFlux?¶
Use WebFlux when: - High concurrency with many concurrent connections - Streaming data - Microservices calling multiple downstream services - Non-blocking I/O operations
Stick with MVC when: - JDBC/JPA (blocking by nature) - Simple CRUD applications - Team unfamiliar with reactive programming
Q30: Microservices Patterns with Spring?¶
// Service Discovery (Eureka)
@EnableDiscoveryClient
// Load Balancing
@LoadBalanced
@Bean
public RestTemplate restTemplate() { }
// Circuit Breaker (Resilience4j)
@CircuitBreaker(name = "payment", fallbackMethod = "paymentFallback")
public Payment processPayment(Order order) { }
// Distributed Tracing
// spring-cloud-starter-sleuth + zipkin
// Config Server
// spring-cloud-config-server
Quick Reference Table¶
| Annotation | Purpose |
|---|---|
| @Component | Generic Spring bean |
| @Service | Business logic layer |
| @Repository | Data access layer |
| @Controller | Web MVC controller |
| @RestController | REST API controller |
| @Configuration | Configuration class |
| @Bean | Method-level bean definition |
| @Autowired | Dependency injection |
| @Value | Property injection |
| @Transactional | Transaction boundary |
| @Cacheable | Cache method result |
| @Async | Async execution |
| @Scheduled | Scheduled task |
| @PreAuthorize | Method-level security |
| @Valid | Bean validation |
- *