Top 50 Spring Boot Interview Questions & Answers (2026)
Spring Boot interviews have a well-known pattern. The same 50 questions appear — in different forms — across companies ranging from Infosys and TCS to Razorpay and PhonePe. The difference between passing and failing is not intelligence. It is preparation.
This guide covers every question category interviewers use, with production-quality answers. Not textbook definitions — the kind of answers that make an interviewer nod and move on.
Category 1: Core Spring Boot Concepts (Q1–Q10)
Q1. What is Spring Boot and how is it different from the Spring Framework?
Spring Framework is a comprehensive framework for building Java applications. It is powerful, but requires a lot of configuration — XML files, Java config classes, dependency wiring.
Spring Boot is an opinionated layer on top of Spring Framework that:
- Auto-configures components based on the JARs present in the classpath
- Provides embedded servers (Tomcat, Jetty, Undertow) — no need to deploy a WAR file
- Offers starter dependencies that bundle compatible library versions
- Includes Spring Boot Actuator for production monitoring out of the box
The one-line answer: Spring Boot makes Spring-based applications production-ready with minimal configuration.
Q2. What is the role of @SpringBootApplication?
It is a convenience annotation that combines three annotations:
@SpringBootApplication
// is equivalent to:
@SpringBootConfiguration // marks this as a configuration class
@EnableAutoConfiguration // triggers Spring Boot's auto-configuration mechanism
@ComponentScan // scans for @Component, @Service, @Repository, @Controller beans
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}Follow-up: If you only want to scan specific packages:
@SpringBootApplication(scanBasePackages = {"com.bigxstar.api", "com.bigxstar.service"})Q3. What is Auto-Configuration in Spring Boot? How does it work?
Auto-configuration automatically configures Spring beans based on what is on the classpath and what properties are set.
How it works:
- When your app starts, Spring Boot reads
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - Each entry is a configuration class annotated with
@ConditionalOn*annotations - The configuration only applies if the condition is met
// Spring Boot's internal DataSource auto-configuration looks roughly like this:
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(DataSource.class) // only if you haven't defined your own
@AutoConfiguration
public class DataSourceAutoConfiguration {
// Configures a DataSource for you automatically
}So if you add spring-boot-starter-data-jpa to your pom.xml, Spring Boot detects it and auto-configures a DataSource, EntityManagerFactory, and TransactionManager.
Q4. What are Spring Boot Starters? Name five commonly used ones.
Starters are pre-packaged sets of dependencies designed to work together. Instead of adding 10 separate library versions (and risking incompatibility), you add one starter.
| Starter | What It Includes |
|---|---|
spring-boot-starter-web | Spring MVC, Tomcat, Jackson (JSON) |
spring-boot-starter-data-jpa | Hibernate, Spring Data JPA, JDBC |
spring-boot-starter-security | Spring Security |
spring-boot-starter-test | JUnit 5, Mockito, AssertJ, Spring Test |
spring-boot-starter-actuator | Production monitoring endpoints |
spring-boot-starter-mail | JavaMail, Spring Email support |
spring-boot-starter-validation | Bean Validation (Hibernate Validator) |
Q5. What is the difference between @Component, @Service, @Repository, and @Controller?
All four are stereotypes — they tell Spring to manage the class as a bean. The difference is semantic and functional:
@Component // generic Spring-managed bean
@Service // business logic layer — same as @Component but signals intent
@Repository // data access layer — adds exception translation (JPA exceptions → Spring DataAccessException)
@Controller // web layer — handles HTTP requests, returns views
@RestController // web layer — @Controller + @ResponseBody (returns JSON/XML)The key functional difference is @Repository: it wraps JPA exceptions into Spring's DataAccessException hierarchy, which makes exception handling consistent.
Q6. What is Dependency Injection (DI)? What are the three types in Spring?
DI is a design pattern where an object receives its dependencies from an external source instead of creating them itself. Spring's IoC container manages this.
// 1. Constructor Injection — PREFERRED (makes dependencies explicit and final)
@Service
public class OrderService {
private final PaymentGateway paymentGateway;
private final InventoryService inventoryService;
public OrderService(PaymentGateway paymentGateway, InventoryService inventoryService) {
this.paymentGateway = paymentGateway;
this.inventoryService = inventoryService;
}
}
// 2. Setter Injection — for optional dependencies
@Service
public class ReportService {
private EmailService emailService;
@Autowired
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
}
// 3. Field Injection — @Autowired on field (NOT recommended — makes testing harder)
@Service
public class UserService {
@Autowired // avoid this in production code
private UserRepository userRepository;
}In interviews: Always say you prefer Constructor Injection and explain why — it makes dependencies immutable and explicit, and works without reflection (making testing straightforward).
Q7. What is the difference between @Bean and @Component?
| Aspect | @Component | @Bean |
|---|---|---|
| Applied to | Class | Method in a @Configuration class |
| When to use | Classes you own | Third-party classes or complex initialization logic |
| Detection | Auto-detected via component scan | Explicitly declared |
// @Component — you own the class
@Component
public class EmailValidator {
public boolean isValid(String email) { ... }
}
// @Bean — third-party class you don't own (e.g., a library's client)
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate rt = new RestTemplate();
rt.setErrorHandler(new CustomErrorHandler());
return rt;
}
}Q8. What is application.properties vs application.yml? Which is better?
Both configure Spring Boot application properties. application.yml is hierarchical and more readable for nested config; application.properties is flat key-value pairs.
# application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=postgres
spring.jpa.hibernate.ddl-auto=update
server.port=8080# application.yml — equivalent, but more readable for nested configs
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: postgres
jpa:
hibernate:
ddl-auto: update
server:
port: 8080For production apps: always externalize sensitive values:
spring:
datasource:
password: ${DB_PASSWORD} # reads from environment variableQ9. What are Spring Profiles? How do you use them?
Profiles let you define different configurations for different environments (dev, staging, production).
# application-dev.yml
spring:
datasource:
url: jdbc:h2:mem:testdb # in-memory for local dev
# application-prod.yml
spring:
datasource:
url: jdbc:postgresql://prod-server:5432/mydbActivate a profile:
# On startup
java -jar myapp.jar --spring.profiles.active=prod
# Or as environment variable
SPRING_PROFILES_ACTIVE=prodIn code:
@Configuration
@Profile("prod")
public class ProdSecurityConfig {
// Only active in production profile
}Q10. What is the difference between @Value and @ConfigurationProperties?
// @Value — for a single property
@Service
public class PaymentService {
@Value("${payment.gateway.api-key}")
private String apiKey;
}
// @ConfigurationProperties — for a group of related properties (PREFERRED for complex config)
@ConfigurationProperties(prefix = "payment.gateway")
@Component
public class PaymentGatewayConfig {
private String apiKey;
private String baseUrl;
private int timeoutSeconds;
private boolean sandboxMode;
// getters + setters
}# application.yml
payment:
gateway:
api-key: sk_live_xxxx
base-url: https://api.payment.com
timeout-seconds: 30
sandbox-mode: false@ConfigurationProperties is preferred because it is type-safe, supports validation with @Validated, and is easier to test.
Category 2: Spring Data JPA & Database (Q11–Q22)
Q11. What is JPA? What is the difference between JPA, Hibernate, and Spring Data JPA?
- JPA (Java Persistence API) — a specification (a set of interfaces and rules) for ORM in Java
- Hibernate — the most popular implementation of the JPA specification
- Spring Data JPA — a layer on top of JPA/Hibernate that reduces boilerplate. It generates implementations of repositories automatically.
Your Code → Spring Data JPA (findByEmail) → JPA (EntityManager) → Hibernate → JDBC → DatabaseQ12. Explain @Entity, @Table, @Id, @GeneratedValue.
@Entity // marks this class as a JPA entity (maps to a table)
@Table(name = "users") // optional: specify table name (default = class name)
public class User {
@Id // marks as primary key
@GeneratedValue(strategy = GenerationType.IDENTITY) // auto-increment
private Long id;
@Column(name = "email_address", nullable = false, unique = true, length = 255)
private String email;
@Column(name = "created_at")
private LocalDateTime createdAt;
}GenerationType strategies:
IDENTITY— database auto-increment (MySQL, PostgreSQL)SEQUENCE— uses a DB sequence (best for PostgreSQL batch inserts)UUID— generates a UUID (good for distributed systems)AUTO— Spring picks the strategy based on the database
Q13. What are the JPA relationship mappings? Explain with examples.
// @OneToMany / @ManyToOne — most common relationship
@Entity
public class Order {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY) // many orders → one customer
@JoinColumn(name = "customer_id")
private Customer customer;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
}
// @ManyToMany
@Entity
public class Student {
@ManyToMany
@JoinTable(
name = "student_courses",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
}Q14. What is the N+1 Problem in JPA? How do you solve it?
// THE PROBLEM:
// Fetching 100 orders fires 1 query for orders + 100 queries for each customer = 101 queries
List<Order> orders = orderRepository.findAll();
for (Order order : orders) {
System.out.println(order.getCustomer().getName()); // triggers a new query each time
}
// SOLUTION 1: JPQL with JOIN FETCH
@Query("SELECT o FROM Order o JOIN FETCH o.customer")
List<Order> findAllWithCustomer();
// SOLUTION 2: Entity Graph
@EntityGraph(attributePaths = {"customer", "items"})
List<Order> findAll();
// SOLUTION 3: Use @BatchSize for lazy collections
@OneToMany(mappedBy = "order")
@BatchSize(size = 20) // loads 20 at a time instead of 1 at a time
private List<OrderItem> items;Always mention the N+1 problem in interviews — it is one of the most common real-world performance issues with JPA, and knowing the solutions signals real production experience.
Q15. What is the difference between FetchType.LAZY and FetchType.EAGER?
- LAZY — related data is loaded only when you access it (the default for
@OneToMany,@ManyToMany) - EAGER — related data is loaded immediately with the parent entity (the default for
@ManyToOne,@OneToOne)
// LAZY — good default, avoids loading unnecessary data
@ManyToOne(fetch = FetchType.LAZY)
private Department department;
// EAGER — use only when you always need the related entity
@ManyToOne(fetch = FetchType.EAGER)
private UserProfile profile;Common mistake: Using FetchType.EAGER everywhere for convenience. This causes massive over-fetching in production. Use LAZY by default and fetch eagerly only when needed with JOIN FETCH.
Q16. What is the difference between save(), saveAndFlush(), and flush() in Spring Data JPA?
// save() — persists or merges, adds to the persistence context, writes to DB at transaction commit
User user = userRepository.save(newUser);
// saveAndFlush() — same as save() but immediately flushes to the DB (within the transaction)
// Use when you need the DB to reflect changes immediately (e.g., before calling a stored procedure)
User user = userRepository.saveAndFlush(newUser);
// flush() — writes all pending changes in the persistence context to the DB
// (does NOT commit the transaction)
userRepository.flush();Q17. What does @Transactional do? What is its propagation behavior?
@Transactional wraps a method in a database transaction — if the method throws an exception, the transaction is rolled back.
@Service
public class OrderService {
@Transactional // starts a transaction, commits on success, rolls back on RuntimeException
public Order placeOrder(OrderRequest request) {
Order order = createOrder(request);
inventoryService.deductStock(request.getItems()); // runs in same transaction
paymentService.charge(request.getPayment()); // runs in same transaction
return order;
// transaction commits here if no exception
}
}Common propagation types:
@Transactional(propagation = Propagation.REQUIRED) // default: join existing or create new
@Transactional(propagation = Propagation.REQUIRES_NEW) // always create a new transaction
@Transactional(propagation = Propagation.SUPPORTS) // join if exists, run without if not
@Transactional(readOnly = true) // optimization for read-only operationsGotcha: @Transactional only works on public methods called from outside the class. Calling a @Transactional method from within the same class bypasses the proxy.
Q18. What is the difference between findById(), getById(), and getReferenceById()?
// findById() — hits the DB immediately, returns Optional<T>
Optional<User> user = userRepository.findById(1L);
// getReferenceById() (formerly getById) — returns a PROXY, no DB hit until you access a field
// Use when you only need the reference (e.g., for a @ManyToOne foreign key)
User userRef = userRepository.getReferenceById(1L); // no DB query yet
order.setUser(userRef); // just sets the foreign key — efficient!
orderRepository.save(order); // DB query happens here for the saveQ19. What are the different ddl-auto strategies in Spring JPA?
spring:
jpa:
hibernate:
ddl-auto: validate # safest for production| Value | Behavior |
|---|---|
none | Do nothing. You manage the schema. |
validate | Validates schema matches entities. Fails fast if mismatch. |
update | Updates schema to match entities. Never use in production. |
create | Creates schema on startup, drops on shutdown. Good for tests. |
create-drop | Creates on startup, drops on shutdown. |
Production rule: Always use none or validate in production. Manage schema changes with Flyway or Liquibase.
Q20. What is Spring Data's custom query support? Explain derived query methods and @Query.
public interface UserRepository extends JpaRepository<User, Long> {
// Derived query methods — Spring generates SQL from method name
List<User> findByLastName(String lastName);
Optional<User> findByEmailIgnoreCase(String email);
List<User> findByAgeGreaterThanOrderByCreatedAtDesc(int age);
boolean existsByEmail(String email);
long countByStatus(UserStatus status);
// @Query — custom JPQL (object-oriented query language)
@Query("SELECT u FROM User u WHERE u.email = :email AND u.active = true")
Optional<User> findActiveUserByEmail(@Param("email") String email);
// @Query with native SQL
@Query(value = "SELECT * FROM users WHERE last_login < NOW() - INTERVAL '30 days'",
nativeQuery = true)
List<User> findInactiveUsers();
// Modifying query
@Modifying
@Transactional
@Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
int updateUserStatus(@Param("id") Long id, @Param("status") UserStatus status);
}Q21. What is the difference between CrudRepository, JpaRepository, and PagingAndSortingRepository?
CrudRepository
└── PagingAndSortingRepository (adds paging/sorting)
└── JpaRepository (adds JPA-specific methods: flush, saveAndFlush, deleteInBatch)Use JpaRepository by default — it gives you everything.
Q22. How do you implement pagination in Spring Boot?
// Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
Page<Product> findByCategory(String category, Pageable pageable);
}
// Service
@Service
public class ProductService {
public Page<Product> getProductsByCategory(String category, int page, int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("price").ascending());
return productRepository.findByCategory(category, pageable);
}
}
// Controller
@GetMapping("/products")
public ResponseEntity<Page<Product>> getProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "electronics") String category) {
return ResponseEntity.ok(productService.getProductsByCategory(category, page, size));
}Response includes: content (list of items), totalElements, totalPages, number, size.
Category 3: REST API & Web Layer (Q23–Q33)
Q23. What is the difference between @Controller and @RestController?
@Controller // returns a view name (for server-side rendering with Thymeleaf etc.)
public class PageController {
@GetMapping("/home")
public String home(Model model) {
model.addAttribute("user", currentUser);
return "home"; // resolves to home.html template
}
}
@RestController // = @Controller + @ResponseBody — returns JSON/XML directly
public class ApiController {
@GetMapping("/api/users")
public List<User> getUsers() {
return userService.findAll(); // serialized to JSON automatically
}
}Q24. What is ResponseEntity? Why use it over returning the object directly?
ResponseEntity gives you full control over the HTTP response: status code, headers, and body.
// Without ResponseEntity — always returns 200 OK, even for created resources
@PostMapping("/users")
public User createUser(@RequestBody UserDTO dto) {
return userService.create(dto); // should be 201, but returns 200
}
// With ResponseEntity — correct HTTP semantics
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody UserDTO dto) {
User created = userService.create(dto);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest().path("/{id}")
.buildAndExpand(created.getId()).toUri();
return ResponseEntity.created(location).body(created); // 201 Created + Location header
}
// Other common patterns
return ResponseEntity.ok(data); // 200
return ResponseEntity.noContent().build(); // 204 (after DELETE)
return ResponseEntity.notFound().build(); // 404
return ResponseEntity.badRequest().body(errors); // 400Q25. How do you handle exceptions globally in Spring Boot?
@RestControllerAdvice // global exception handler for all @RestController classes
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
ErrorResponse error = new ErrorResponse("NOT_FOUND", ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationErrors(MethodArgumentNotValidException ex) {
List<String> errors = ex.getBindingResult().getFieldErrors()
.stream()
.map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
.collect(Collectors.toList());
return ResponseEntity.badRequest().body(new ErrorResponse("VALIDATION_FAILED", errors));
}
@ExceptionHandler(Exception.class) // catch-all
public ResponseEntity<ErrorResponse> handleGeneric(Exception ex) {
log.error("Unexpected error", ex);
return ResponseEntity.internalServerError()
.body(new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred"));
}
}Q26. How does Bean Validation work in Spring Boot?
// 1. Add @Valid to the controller parameter
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request) {
return ResponseEntity.ok(userService.create(request));
}
// 2. Add constraints to your DTO
public class CreateUserRequest {
@NotBlank(message = "Name cannot be empty")
@Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters")
private String name;
@NotBlank
@Email(message = "Invalid email format")
private String email;
@NotBlank
@Pattern(regexp = "^(?=.*[A-Z])(?=.*\\d).{8,}$",
message = "Password must be at least 8 chars with one uppercase and one digit")
private String password;
@NotNull
@Min(value = 18, message = "Must be at least 18 years old")
private Integer age;
}If validation fails, Spring throws MethodArgumentNotValidException — caught by your @RestControllerAdvice.
Q27. What is the difference between @PathVariable, @RequestParam, and @RequestBody?
// @PathVariable — extracts a value from the URL path
// GET /products/42
@GetMapping("/products/{id}")
public Product getProduct(@PathVariable Long id) { ... }
// @RequestParam — extracts query parameters from the URL
// GET /products?category=electronics&page=0&size=10
@GetMapping("/products")
public Page<Product> getProducts(
@RequestParam String category,
@RequestParam(defaultValue = "0") int page,
@RequestParam(required = false) String sort) { ... }
// @RequestBody — deserializes the HTTP request body (JSON → Java object)
// POST /products — body: {"name": "Laptop", "price": 50000}
@PostMapping("/products")
public Product createProduct(@RequestBody @Valid ProductDTO dto) { ... }Q28. How do you implement CORS in Spring Boot?
// Method 1: @CrossOrigin on controller (for specific endpoints)
@CrossOrigin(origins = "https://bigxstar.com")
@RestController
public class ProductController { ... }
// Method 2: Global CORS configuration (recommended)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://bigxstar.com", "https://www.bigxstar.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}Q29. What is the difference between PUT and PATCH?
// PUT — replaces the entire resource
@PutMapping("/users/{id}")
public User updateUser(@PathVariable Long id, @RequestBody @Valid UserUpdateRequest request) {
// ALL fields of the user are replaced with the request body
return userService.replace(id, request);
}
// PATCH — partially updates a resource (only the provided fields change)
@PatchMapping("/users/{id}")
public User partialUpdate(@PathVariable Long id, @RequestBody Map<String, Object> updates) {
return userService.partialUpdate(id, updates);
}Q30. How do you log requests and responses in Spring Boot?
@Component
public class RequestLoggingFilter extends OncePerRequestFilter {
private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
try {
filterChain.doFilter(request, response);
} finally {
long duration = System.currentTimeMillis() - startTime;
log.info("{} {} {} {}ms",
request.getMethod(),
request.getRequestURI(),
response.getStatus(),
duration);
}
}
}Or use Spring Boot's built-in CommonsRequestLoggingFilter:
@Bean
public CommonsRequestLoggingFilter logFilter() {
CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(true);
filter.setMaxPayloadLength(10000);
return filter;
}Q31. What is Spring Boot Actuator?
Actuator adds production-ready features via HTTP endpoints:
# application.yml
management:
endpoints:
web:
exposure:
include: health, info, metrics, env # expose only what you need
endpoint:
health:
show-details: alwaysKey endpoints:
/actuator/health— application health (DB connectivity, disk space, etc.)/actuator/info— app info (version, git commit)/actuator/metrics— JVM metrics, HTTP request counts, latency/actuator/env— active configuration properties/actuator/loggers— view and change log levels at runtime (no restart needed)/actuator/threaddump— JVM thread dump
Security note: Always secure Actuator endpoints in production. Expose only /health and /info publicly. Secure the rest behind authentication.
Q32. How do you implement caching in Spring Boot?
// 1. Enable caching
@SpringBootApplication
@EnableCaching
public class MyApplication { ... }
// 2. Configure cache provider (Redis, Caffeine, etc.)
// In application.yml:
// spring.cache.type=redis OR spring.cache.type=caffeine
// 3. Use cache annotations
@Service
public class ProductService {
@Cacheable(value = "products", key = "#id") // cache the result
public Product findById(Long id) {
return productRepository.findById(id).orElseThrow();
}
@CacheEvict(value = "products", key = "#product.id") // remove from cache on update
public Product update(Product product) {
return productRepository.save(product);
}
@CachePut(value = "products", key = "#result.id") // update cache with new value
public Product create(Product product) {
return productRepository.save(product);
}
@CacheEvict(value = "products", allEntries = true) // clear entire cache
public void clearProductCache() { }
}Q33. How do you schedule tasks in Spring Boot?
@SpringBootApplication
@EnableScheduling
public class MyApplication { ... }
@Component
public class ScheduledTasks {
// Fixed rate — every 5 minutes, regardless of execution time
@Scheduled(fixedRate = 300000)
public void syncInventory() { ... }
// Fixed delay — 5 minutes AFTER the previous execution finishes
@Scheduled(fixedDelay = 300000)
public void cleanTempFiles() { ... }
// Cron expression — every day at 2:30 AM
@Scheduled(cron = "0 30 2 * * ?")
public void generateDailyReport() { ... }
// Cron — every weekday at 9 AM IST
@Scheduled(cron = "0 0 9 * * MON-FRI", zone = "Asia/Kolkata")
public void sendMorningDigest() { ... }
}Category 4: Spring Security (Q34–Q40)
Q34. What is Spring Security? How does it work at a high level?
Spring Security is a highly customizable authentication and access control framework.
The request flow:
HTTP Request
→ Security Filter Chain (multiple filters in order)
→ Authentication Filter (checks credentials)
→ Authorization Filter (checks permissions)
→ DispatcherServlet
→ ControllerEvery request passes through the SecurityFilterChain. Key filters:
UsernamePasswordAuthenticationFilter— handles form-based loginJwtAuthenticationFilter(custom) — validates JWT tokensExceptionTranslationFilter— converts security exceptions to HTTP responses
Q35. How do you implement JWT authentication in Spring Boot?
// 1. Create JWT utility
@Component
public class JwtUtils {
@Value("${app.jwt.secret}")
private String jwtSecret;
@Value("${app.jwt.expiration-ms}")
private int jwtExpirationMs;
public String generateToken(String username) {
return Jwts.builder()
.subject(username)
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + jwtExpirationMs))
.signWith(getSigningKey())
.compact();
}
public String extractUsername(String token) {
return Jwts.parser().verifyWith(getSigningKey()).build()
.parseSignedClaims(token).getPayload().getSubject();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
}
}
// 2. JWT filter
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
String jwt = authHeader.substring(7);
String username = jwtUtils.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtUtils.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}Q36. What is the difference between @Secured, @PreAuthorize, and @RolesAllowed?
@EnableMethodSecurity // enables method-level security annotations
// @Secured — simple role check
@Secured("ROLE_ADMIN")
public void deleteUser(Long id) { ... }
// @PreAuthorize — SpEL expressions, more powerful
@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
public User getUser(Long userId) { ... }
// Check if the user owns the resource before updating
@PreAuthorize("@securityService.isResourceOwner(#id, authentication.name)")
public Product updateProduct(Long id, ProductDTO dto) { ... }
// @PostAuthorize — check after method execution (rare)
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(Long id) { ... }Use @PreAuthorize — it is the most flexible and is the current Spring Security recommendation.
Q37. How do you store passwords securely in Spring Boot?
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // cost factor 12 — balances security and speed
}
// In your registration flow:
@Service
public class AuthService {
@Autowired private PasswordEncoder passwordEncoder;
public User register(RegisterRequest request) {
User user = new User();
user.setEmail(request.getEmail());
user.setPassword(passwordEncoder.encode(request.getPassword())); // NEVER store plaintext
return userRepository.save(user);
}
public boolean verifyPassword(String rawPassword, String encodedPassword) {
return passwordEncoder.matches(rawPassword, encodedPassword);
}
}Never store plaintext passwords. Always use BCryptPasswordEncoder or Argon2PasswordEncoder.
Q38. What is CSRF? Does Spring Boot disable it by default for REST APIs?
CSRF (Cross-Site Request Forgery) is an attack where a malicious site tricks a logged-in user's browser into making unauthorized requests.
For stateful web apps (session-based auth), CSRF protection is essential.
For stateless REST APIs (JWT-based), CSRF is not needed because:
- There are no cookies containing session IDs
- JWT tokens are sent in the
Authorizationheader, which browser-initiated cross-site requests cannot set
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // safe to disable for stateless JWT APIs
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.build();
}Category 5: Testing (Q39–Q44)
Q39. What is the difference between @SpringBootTest, @WebMvcTest, and @DataJpaTest?
// @SpringBootTest — loads FULL application context. Use for integration tests.
// Slow — use sparingly.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderIntegrationTest { ... }
// @WebMvcTest — loads ONLY the web layer (controllers, filters, security).
// Fast — for unit testing controllers.
@WebMvcTest(ProductController.class)
class ProductControllerTest {
@Autowired MockMvc mockMvc;
@MockBean ProductService productService; // mock service layer
}
// @DataJpaTest — loads ONLY JPA layer (repositories, entities).
// Uses in-memory H2 database by default. Fast.
@DataJpaTest
class UserRepositoryTest {
@Autowired UserRepository userRepository;
@Autowired TestEntityManager entityManager;
}Q40. How do you write a controller test with MockMvc?
@WebMvcTest(ProductController.class)
@AutoConfigureMockMvc(addFilters = false) // disable security filters for unit tests
class ProductControllerTest {
@Autowired private MockMvc mockMvc;
@Autowired private ObjectMapper objectMapper;
@MockBean private ProductService productService;
@Test
void getProduct_whenExists_returns200() throws Exception {
Product product = new Product(1L, "Laptop", new BigDecimal("50000"));
when(productService.findById(1L)).thenReturn(Optional.of(product));
mockMvc.perform(get("/api/products/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.name").value("Laptop"))
.andExpect(jsonPath("$.price").value(50000));
}
@Test
void createProduct_withInvalidData_returns400() throws Exception {
ProductDTO dto = new ProductDTO("", null); // invalid: name empty, price null
mockMvc.perform(post("/api/products")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(dto)))
.andExpect(status().isBadRequest());
}
}Q41. What is Mockito? How do you use @Mock vs @MockBean?
// @Mock — pure Mockito, no Spring context. Use in unit tests.
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock private OrderRepository orderRepository;
@Mock private PaymentGateway paymentGateway;
@InjectMocks private OrderService orderService; // injects mocks into the service
@Test
void placeOrder_whenPaymentSucceeds_savesOrder() {
when(paymentGateway.charge(any())).thenReturn(PaymentResult.success("txn_123"));
when(orderRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
Order result = orderService.placeOrder(testRequest);
assertThat(result.getStatus()).isEqualTo(OrderStatus.CONFIRMED);
verify(orderRepository, times(1)).save(any(Order.class));
}
}
// @MockBean — Spring Boot's Mockito, replaces the bean in Spring context.
// Use in @WebMvcTest or @SpringBootTest.
@WebMvcTest(OrderController.class)
class OrderControllerTest {
@MockBean private OrderService orderService; // replaces real OrderService in Spring context
}Category 6: Microservices & Advanced (Q42–50)
Q42. What are microservices? How does Spring Boot support them?
Microservices is an architectural style where an application is split into small, independent services, each running its own process and communicating over HTTP/messaging.
Spring Boot supports microservices through:
- Spring Cloud — service discovery, config server, circuit breakers
- Spring Cloud Netflix Eureka — service registry
- Spring Cloud Gateway — API gateway
- Feign Client — declarative HTTP clients between services
- Spring Cloud Config — centralized external configuration
- Spring Cloud Circuit Breaker (Resilience4j) — fault tolerance
Q43. What is a Feign Client?
// Instead of using RestTemplate manually, Feign generates the HTTP client for you:
@FeignClient(name = "inventory-service", url = "${inventory.service.url}")
public interface InventoryClient {
@GetMapping("/api/inventory/{productId}")
InventoryResponse checkStock(@PathVariable Long productId);
@PostMapping("/api/inventory/deduct")
void deductStock(@RequestBody DeductRequest request);
}
// Use it like any other @Autowired bean
@Service
public class OrderService {
@Autowired private InventoryClient inventoryClient;
public Order placeOrder(OrderRequest request) {
InventoryResponse stock = inventoryClient.checkStock(request.getProductId());
if (stock.getQuantity() < request.getQuantity()) {
throw new InsufficientStockException();
}
// ...
}
}Q44. What is a Circuit Breaker? How does Resilience4j implement it?
A Circuit Breaker prevents cascading failures. If a downstream service is failing repeatedly, the circuit "opens" and subsequent calls fail fast (without waiting for a timeout).
@Service
public class ProductService {
@CircuitBreaker(name = "inventoryService", fallbackMethod = "fallbackInventory")
@TimeLimiter(name = "inventoryService")
public CompletableFuture<InventoryResponse> checkInventory(Long productId) {
return CompletableFuture.supplyAsync(() -> inventoryClient.checkStock(productId));
}
// Called when circuit is open or timeout occurs
public CompletableFuture<InventoryResponse> fallbackInventory(Long productId, Throwable t) {
log.warn("Inventory service unavailable, using fallback", t);
return CompletableFuture.completedFuture(InventoryResponse.unknown());
}
}# application.yml
resilience4j:
circuitbreaker:
instances:
inventoryService:
slidingWindowSize: 10
failureRateThreshold: 50 # open if 50% of last 10 calls fail
waitDurationInOpenState: 30s # wait 30s before trying again (half-open)Q45. How does Spring Boot handle asynchronous processing?
@SpringBootApplication
@EnableAsync
public class MyApplication { ... }
@Service
public class EmailService {
@Async // runs in a separate thread pool
public CompletableFuture<Void> sendWelcomeEmail(String email) {
// This runs asynchronously — the controller returns immediately
emailSender.send(email, "Welcome to BigXStar!", buildWelcomeBody(email));
return CompletableFuture.completedFuture(null);
}
}
// Configure the async thread pool
@Configuration
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
}Q46. What is the difference between @Transactional rollback on checked vs unchecked exceptions?
// DEFAULT: only rolls back on RuntimeException (unchecked) and Error
@Transactional
public void processOrder(Order order) {
orderRepository.save(order);
throw new IOException("file error"); // DOES NOT rollback — checked exception!
}
// SOLUTION: configure rollbackFor
@Transactional(rollbackFor = Exception.class) // rollback on any exception
public void processOrder(Order order) throws IOException {
orderRepository.save(order);
throw new IOException("file error"); // NOW rolls back
}
// Or: wrap checked exceptions in RuntimeException
@Transactional
public void processOrder(Order order) {
try {
orderRepository.save(order);
riskyOperation();
} catch (IOException e) {
throw new RuntimeException("Processing failed", e); // triggers rollback
}
}Q47. How do you handle database migrations in Spring Boot?
Use Flyway (most common in enterprise Java):
<!-- pom.xml -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>-- src/main/resources/db/migration/V1__create_users_table.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- src/main/resources/db/migration/V2__add_user_roles.sql
ALTER TABLE users ADD COLUMN role VARCHAR(50) DEFAULT 'USER';Flyway runs migrations on startup, in version order. Each migration runs exactly once.
spring:
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: trueQ48. What is the difference between @Autowired on a field, constructor, and setter?
Always prefer constructor injection for these reasons:
- Immutability — dependencies can be
final - Fail-fast — missing dependency fails at startup, not at runtime
- Testability — no Spring context needed in unit tests:
// With field injection — needs Spring to test
@Autowired private OrderRepository orderRepository; // can't inject without Spring
// With constructor injection — pure Java object creation in tests
OrderService service = new OrderService(mockRepository, mockGateway); // no Spring neededQ49. What is @Conditional and name some @ConditionalOn* annotations?
@Conditional allows bean registration only when a condition is met.
@Bean
@ConditionalOnProperty(name = "feature.payments.enabled", havingValue = "true")
public PaymentGateway stripeGateway() {
return new StripeGateway(apiKey);
}
@Bean
@ConditionalOnMissingBean(CacheManager.class) // only if no CacheManager is defined
public CacheManager simpleCacheManager() {
return new SimpleCacheManager();
}
@Bean
@ConditionalOnClass(name = "com.amazonaws.services.s3.AmazonS3") // only if AWS SDK is present
public S3FileStorage s3FileStorage() { ... }
@ConditionalOnWebApplication // only in a web application context
@ConditionalOnNotWebApplication // only in a non-web context
@ConditionalOnExpression("${app.environment} == 'production'")Q50. What are the best practices for a production-ready Spring Boot application?
// 1. Use constructor injection everywhere
// 2. Externalize ALL configuration
spring.datasource.password=${DB_PASSWORD} // never hardcode secrets
// 3. Always validate input
@Valid @RequestBody CreateOrderRequest request
// 4. Use specific exception handling
@RestControllerAdvice with specific @ExceptionHandler methods
// 5. Use @Transactional(readOnly = true) for read operations
@Transactional(readOnly = true)
public List<Product> getAll() { return productRepository.findAll(); }
// 6. Set connection pool limits
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=30000
// 7. Enable and secure Actuator
management.endpoints.web.exposure.include=health,info
// 8. Use Flyway for schema migrations
// 9. Add structured logging with MDC for tracing
MDC.put("requestId", UUID.randomUUID().toString());
// 10. Profile-based configuration
@Profile("prod")
public class ProductionSecurityConfig { ... }Final Preparation Checklist
Before your Spring Boot interview, make sure you can:
- Explain the Spring Boot auto-configuration mechanism clearly
- Write a complete REST API endpoint with validation and error handling
- Explain the N+1 problem and its solutions without prompting
- Implement JWT authentication from scratch
- Write a unit test using
@WebMvcTestand a repository test using@DataJpaTest - Explain constructor vs field injection and why you prefer constructor
- Describe what
@Transactionaldoes and when it does NOT roll back - Explain at least one microservices pattern (Circuit Breaker, Service Discovery)
What Next?
Knowing the answers is only half the battle. You need to have built something real with these concepts before an interviewer probes deeper.
If you want structured, project-based Spring Boot training — where you build full applications under code review — explore BigXStar's Java Full Stack Course. For those preparing for senior roles at product companies, our Java Full Stack Career Program covers Spring Boot, microservices, system design, and interview preparation over 9 months.
Good luck — and remember, the goal is not to memorize these answers. It is to have built enough to mean every word you say.