Top 45 Spring Boot Interview Questions & Answers (2026)
About Spring Boot
Top 100 Spring Boot interview questions covering auto-configuration, dependency injection, REST APIs, Spring Data JPA, Spring Security, microservices, testing, and production deployment. Companies hiring for Spring Boot roles test this knowledge at every stage — from first-round screens that check the basics to final-round conversations about real-world trade-offs.
What to Expect in a Spring Boot Interview
Expect a mix of conceptual and practical Spring Boot questions: clear definitions and core-concept checks for junior roles, hands-on scenario questions for mid-level roles, and architecture or trade-off discussions for senior roles. Interviewers usually move from foundational topics toward the kind of problems you'd actually face on the job.
How to Use This Guide
Work through the Spring Boot questions in order — Beginner, then Intermediate, then Advanced — so each concept builds on the last. Every question has its own page; bookmark the ones that trip you up and revisit them the day before your interview.
Curated by Tech Baithak Editorial Team · Last updated: May 2026
Core concepts every Spring Boot developer must know.
01
What is Spring Boot?
Spring Boot is an opinionated, convention-over-configuration extension of the Spring Framework that simplifies bootstrapping and developing Spring-based applications. Released in 2014 by Pivotal (now VMware), it eliminates most of the boilerplate XML configuration and manual dependency management required in traditional Spring applications. Key features: (1) Auto-configuration: automatically configures Spring application based on the dependencies on the classpath; (2) Starter dependencies: curated dependency descriptors that group related dependencies together (spring-boot-starter-web, spring-boot-starter-data-jpa); (3) Embedded servers: includes embedded Tomcat, Jetty, or Undertow — no need to deploy WAR files; (4) Actuator: production-ready monitoring and management endpoints; (5) Spring Initializr: start.spring.io — web tool to generate project structure; (6) No XML configuration: Java-based configuration with annotations. Spring Boot is the most popular Java web framework, used at Netflix, Amazon, Alibaba, eBay, and most enterprises building Java microservices.
02
What is the difference between Spring and Spring Boot?
Spring Framework is a comprehensive, powerful Java application framework for dependency injection, AOP, data access, MVC, etc. It requires significant manual configuration: XML files or Java config classes for every component, dependency management (ensuring compatible versions), web server setup (external Tomcat), and component scanning configuration. Spring Boot builds on top of Spring Framework and dramatically simplifies setup: (1) Auto-configuration: Spring Boot auto-configures application based on classpath. Add spring-boot-starter-web → auto-configures DispatcherServlet, Jackson, Tomcat. No manual configuration needed; (2) Opinionated defaults: provides sensible defaults for everything; (3) Starter POMs: single dependency bundles all related libraries with compatible versions; (4) Embedded server: Tomcat embedded — just run a main class; (5) No XML: annotation-based configuration is standard. What Spring Boot does NOT change: Spring Boot IS Spring under the hood — all Spring Framework features (DI, AOP, Spring Data, Spring Security, Spring MVC) are used as-is. Spring Boot just reduces the setup friction. Analogy: Spring is a powerful engine; Spring Boot is the ready-to-drive car built on that engine — you can still access and modify the engine, but most things just work out of the box.
03
What is auto-configuration in Spring Boot?
Auto-configuration is Spring Boot's core feature that automatically configures Spring beans based on: (1) Dependencies on the classpath; (2) Existing beans in the application context; (3) Properties defined in application.properties/yaml. How it works: Spring Boot includes over 100 auto-configuration classes annotated with @Configuration. Each uses @Conditional annotations to activate only when specific conditions are met. Example: DataSourceAutoConfiguration fires when spring-jdbc is on the classpath AND no DataSource bean is defined. @SpringBootApplication meta-annotation includes @EnableAutoConfiguration which imports AutoConfigurationImportSelector — reads all auto-configuration class names from META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports and applies conditional ones. Conditional annotations: @ConditionalOnClass(DataSource.class) — active only if DataSource class is on classpath; @ConditionalOnMissingBean(DataSource.class) — active only if no DataSource bean exists (allows override); @ConditionalOnProperty("spring.jpa.enabled"); @ConditionalOnWebApplication. Seeing what's configured: run with --debug flag or spring.boot.admin.server.enabled=true — prints conditions evaluation report. Overriding: define your own bean of the same type → auto-configured bean is disabled. Use @SpringBootTest to test auto-configuration behavior.
04
What is @SpringBootApplication annotation?
@SpringBootApplication is a convenience annotation that combines three annotations: (1) @Configuration: marks the class as a source of bean definitions. Equivalent to a Spring XML configuration file — methods annotated with @Bean create Spring-managed beans; (2) @EnableAutoConfiguration: enables Spring Boot's auto-configuration mechanism. Tells Spring Boot to automatically configure the application based on classpath dependencies and existing beans; (3) @ComponentScan: enables component scanning — Spring searches the package (and sub-packages) of the annotated class for Spring components (@Component, @Service, @Repository, @Controller, @RestController). Usage: @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }. Customization: @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) — exclude specific auto-configurations. @SpringBootApplication(scanBasePackages = {"com.example.service", "com.example.repo"}) — customize scan packages. SpringApplication.run(): creates the application context, triggers auto-configuration, starts the embedded server, and deploys the application. Returns ConfigurableApplicationContext. Main class location: put in the root package (e.g., com.example) so @ComponentScan includes all sub-packages automatically.
05
What are Spring Boot starter dependencies?
Spring Boot starters are dependency descriptors that bundle all necessary dependencies for a specific feature with compatible, tested versions. They follow the naming pattern: spring-boot-starter-{feature}. Common starters: spring-boot-starter-web — Spring MVC, embedded Tomcat, Jackson (JSON), validation; spring-boot-starter-data-jpa — Spring Data JPA, Hibernate, Spring ORM; spring-boot-starter-security — Spring Security; spring-boot-starter-test — JUnit 5, Mockito, AssertJ, Spring Test, MockMvc; spring-boot-starter-data-redis — Spring Data Redis, Lettuce client; spring-boot-starter-data-mongodb — Spring Data MongoDB; spring-boot-starter-cache — Spring caching support; spring-boot-starter-actuator — production monitoring; spring-boot-starter-validation — Bean Validation (Hibernate Validator); spring-boot-starter-mail — JavaMail, Spring Email; spring-boot-starter-amqp — Spring AMQP, RabbitMQ; spring-boot-starter-webflux — Spring WebFlux (reactive), Reactor Netty; spring-boot-starter-thymeleaf — Thymeleaf template engine. Parent POM: spring-boot-starter-parent manages versions for all starters — inherit it to get version management for free. spring-boot-dependencies BOM contains hundreds of dependency versions — used when you can't use the parent POM.
06
What is @RestController in Spring Boot?
@RestController is a convenience annotation that combines @Controller and @ResponseBody. It marks a class as a REST API controller where every method automatically serializes its return value to the HTTP response body (typically JSON) without needing @ResponseBody on each method. @Controller alone is used for MVC controllers that return view names (HTML templates). Example: @RestController @RequestMapping("/api/users") public class UserController { @Autowired private UserService userService; @GetMapping public List<User> getAllUsers() { return userService.findAll(); } @GetMapping("/{id}") public ResponseEntity<User> getUserById(@PathVariable Long id) { return userService.findById(id).map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build()); } @PostMapping public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request) { User user = userService.create(request); return ResponseEntity.status(HttpStatus.CREATED).body(user); } @PutMapping("/{id}") public User updateUser(@PathVariable Long id, @RequestBody UpdateUserRequest request) { return userService.update(id, request); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.delete(id); return ResponseEntity.noContent().build(); } }. Jackson automatically serializes Java objects to JSON and deserializes JSON request bodies.
07
What are Spring MVC request mapping annotations?
Spring MVC provides several annotations for mapping HTTP requests to handler methods: @RequestMapping: base annotation — maps requests by URL, method, headers, parameters: @RequestMapping(value = "/users", method = RequestMethod.GET). Can be used at class and method level. Shorthand method-specific annotations: @GetMapping("/users") — HTTP GET; @PostMapping("/users") — HTTP POST; @PutMapping("/users/{id}") — HTTP PUT; @PatchMapping("/users/{id}") — HTTP PATCH; @DeleteMapping("/users/{id}") — HTTP DELETE. Parameter extraction annotations: @PathVariable Long id — extract from URL path: /users/{id}; @RequestParam String name — extract from query string: ?name=Alice (optional with defaultValue); @RequestBody User user — deserialize request body from JSON; @RequestHeader("Authorization") String token — extract from request header; @CookieValue("sessionId") String sessionId. ResponseEntity: wrap return value to control HTTP status, headers, and body: return ResponseEntity.status(201).header("Location", "/users/" + id).body(user);. @ResponseStatus: set default status for a method: @ResponseStatus(HttpStatus.CREATED). Multiple paths: @GetMapping({"/", "/home", "/index"}). Content negotiation: @GetMapping(produces = "application/json"), @PostMapping(consumes = "application/json").
08
What is Spring Boot application.properties/application.yaml?
Spring Boot uses application.properties or application.yaml (in src/main/resources/) as the primary configuration file for setting application properties. They configure both Spring Boot auto-configuration and custom application settings. Properties format: server.port=8080 spring.datasource.url=jdbc:postgresql://localhost:5432/mydb spring.datasource.username=postgres spring.datasource.password=secret spring.jpa.hibernate.ddl-auto=validate spring.jpa.show-sql=true logging.level.com.example=DEBUG app.jwt.secret=mySecretKey app.max-upload-size=10MB. YAML format (recommended for hierarchy): server: port: 8080 spring: datasource: url: jdbc:postgresql://localhost:5432/mydb username: postgres jpa: show-sql: true app: jwt: secret: mySecretKey. Profiles: create application-dev.properties, application-prod.properties — activated with spring.profiles.active=dev. External config: Spring Boot loads properties in priority order: 1. Command-line args (--server.port=9090); 2. Environment variables (SPRING_DATASOURCE_URL); 3. application-{profile}.properties; 4. application.properties. @Value injection: @Value("${app.jwt.secret}") private String jwtSecret;. @ConfigurationProperties: bind a prefix to a POJO for type-safe configuration: @ConfigurationProperties(prefix = "app.jwt") public class JwtProperties { private String secret; private int expiration; }.
09
What is Dependency Injection in Spring?
Dependency Injection (DI) is a core Spring Framework pattern where objects don't create their dependencies themselves — they declare them and Spring's IoC (Inversion of Control) container provides them. Types of DI in Spring: (1) Constructor Injection (recommended): @Service public class OrderService { private final PaymentService paymentService; private final EmailService emailService; @Autowired // optional with single constructor in Spring 4.3+ public OrderService(PaymentService paymentService, EmailService emailService) { this.paymentService = paymentService; this.emailService = emailService; } }. Benefits: dependencies are final (immutable), easier testing (pass mocks via constructor), clearly visible dependencies; (2) Setter Injection: @Autowired public void setPaymentService(PaymentService ps) { this.paymentService = ps; }. Use for optional dependencies; (3) Field Injection (avoid): @Autowired private PaymentService paymentService;. Cannot make final, harder to test, hides dependencies — avoid in production code. @Autowired: Spring automatically wires the bean of the matching type. @Qualifier: when multiple beans of the same type exist: @Autowired @Qualifier("primaryPaymentService"). @Primary: mark a bean as the default when multiple exist. IoC Container: Spring's ApplicationContext manages bean creation, lifecycle, and injection. Beans are singletons by default (one instance per application context).
10
What is the Spring IoC Container?
The Inversion of Control (IoC) Container is the central Spring Framework component responsible for creating, managing, configuring, and wiring application objects (beans). "Inversion of Control" means the framework manages object creation instead of the application code doing it (new MyService()). Interfaces: BeanFactory — basic container, lazy initialization; ApplicationContext — extends BeanFactory with: eager initialization, internationalization (i18n), event publishing, AOP support. In Spring Boot, the ApplicationContext is a AnnotationConfigServletWebServerApplicationContext (for web apps). Getting the context: @Autowired ApplicationContext context; context.getBean(UserService.class); or implement ApplicationContextAware. Bean creation: Spring reads: @Component annotations (component scan), @Bean methods in @Configuration classes, XML bean definitions (legacy). Creates instances using reflection, wires dependencies, applies AOP, manages lifecycle. Bean scopes: @Scope("singleton") (default) — one instance per context; @Scope("prototype") — new instance per injection/request; @Scope("request") — new per HTTP request; @Scope("session") — new per HTTP session; @Scope("application") — one per ServletContext. Lifecycle callbacks: @PostConstruct — called after injection (initialization); @PreDestroy — called before bean is destroyed (cleanup). InitializingBean.afterPropertiesSet() and DisposableBean.destroy() also work.
11
What are Spring stereotype annotations?
Spring stereotype annotations mark classes for component scanning and indicate their role in the application: @Component: generic Spring-managed component. Base annotation; use when no more specific annotation applies: utility classes, helpers. @Service: marks a service layer class — business logic, use cases. Functionally identical to @Component, but semantically indicates service layer. @Repository: marks a data access layer class. In addition to component behavior, adds PersistenceExceptionTranslation — converts JDBC/JPA exceptions to Spring's DataAccessException hierarchy for consistent error handling. @Controller: marks an MVC controller that handles HTTP requests and returns view names (for template engines). @RestController: @Controller + @ResponseBody — returns data (JSON) directly. @Configuration: marks a class as a bean definition source. Methods annotated with @Bean in this class create Spring beans. @ControllerAdvice / @RestControllerAdvice: applies to all controllers — global exception handling (@ExceptionHandler), model attributes. Component scanning: @SpringBootApplication (via @ComponentScan) automatically discovers all annotated classes in the main class's package and sub-packages. Custom stereotypes: create your own by annotating an annotation with @Component: @Component @Target(TYPE) @Retention(RUNTIME) public @interface Facade {}. Naming: Spring uses lowercase class name as bean name by default (UserService → userService). Customize: @Service("myUserService").
12
What is Spring Data JPA?
Spring Data JPA is a Spring Data module that drastically simplifies working with JPA (Java Persistence API) databases by eliminating boilerplate repository code. JpaRepository: extends CrudRepository and PagingAndSortingRepository. Provides: save(), findById(), findAll(), delete(), count(), existsById(), findAll(Pageable), findAll(Sort). public interface UserRepository extends JpaRepository<User, Long> { // Query derived from method name: List<User> findByEmailAndStatus(String email, String status); List<User> findByAgeBetween(int min, int max); Optional<User> findByEmail(String email); long countByStatus(String status); // Custom JPQL query: @Query("SELECT u FROM User u WHERE u.name LIKE %:name% AND u.active = true") List<User> searchActive(@Param("name") String name); // Native SQL query: @Query(value = "SELECT * FROM users WHERE MATCH(bio) AGAINST(:term)", nativeQuery = true) List<User> fullTextSearch(@Param("term") String term); @Modifying @Query("UPDATE User u SET u.status = :status WHERE u.id = :id") void updateStatus(@Param("id") Long id, @Param("status") String status); }. @Entity: marks a class as JPA entity (database table). @Id, @GeneratedValue: primary key and generation strategy. Pagination: userRepository.findAll(PageRequest.of(0, 10, Sort.by("createdAt").descending())). Auditing: @EntityListeners(AuditingEntityListener.class) with @CreatedDate, @LastModifiedDate — auto-populate timestamps.
13
What is Spring Boot Actuator?
Spring Boot Actuator provides production-ready management and monitoring endpoints for Spring Boot applications. Add: spring-boot-starter-actuator. Built-in endpoints (at /actuator/{endpoint}): /actuator/health — application health status (UP/DOWN) and component health; /actuator/info — application info (from application.properties or git info); /actuator/metrics — detailed metrics (JVM memory, CPU, HTTP requests, custom metrics); /actuator/env — environment properties and configuration; /actuator/beans — all beans in the application context; /actuator/mappings — all request mappings; /actuator/loggers — view and modify log levels at runtime; /actuator/threaddump — thread dump; /actuator/heapdump — heap dump; /actuator/httptrace — recent HTTP requests; /actuator/shutdown — graceful shutdown (disabled by default). Configuration: management.endpoints.web.exposure.include=health,info,metrics,loggers management.endpoint.health.show-details=always management.server.port=8081 # Separate port for actuator. Security: restrict actuator endpoints — require authentication. Use Spring Security to protect /actuator/** with ACTUATOR role. Expose only needed endpoints. Custom health indicator: implement HealthIndicator interface to add custom health checks. Metrics integration: Actuator integrates with Micrometer — expose metrics to Prometheus/Grafana/Datadog.
14
What are Spring profiles?
Spring profiles allow defining different configurations for different environments (development, testing, production) within the same application. Beans and properties can be conditionally activated based on the active profile. Defining profile-specific properties: create files: application-dev.properties (dev profile), application-prod.properties (prod profile), application-test.properties (test profile). Properties in profile-specific files override application.properties. Activating profiles: property file: spring.profiles.active=dev,aws; command line: java -jar app.jar --spring.profiles.active=prod; environment variable: SPRING_PROFILES_ACTIVE=prod; in tests: @ActiveProfiles("test"). Profile-specific beans: @Profile("dev") @Bean public DataSource h2DataSource() { ... } @Profile("prod") @Bean public DataSource postgresDataSource() { ... } @Profile("!prod") @Service public class MockEmailService implements EmailService { ... }. @Profile on @Configuration: entire configuration class active only for a profile. Profile groups (Spring Boot 2.4+): group profiles: spring.profiles.group.production=prod,cloud,monitoring — activating "production" activates all three. Default profile: beans with no @Profile are always active. Beans with @Profile("default") are active when no other profile is active. Conditional beans without profiles: use @Conditional annotations for more flexible conditions.
15
What is Spring Boot logging?
Spring Boot uses SLF4J (Simple Logging Facade for Java) as the logging API and Logback as the default implementation (included in spring-boot-starter). Using a logger: import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Service public class UserService { private static final Logger log = LoggerFactory.getLogger(UserService.class); public User createUser(String email) { log.debug("Creating user: {}", email); // {} is placeholder try { User user = userRepository.save(new User(email)); log.info("User created: id={}, email={}", user.getId(), email); return user; } catch (Exception e) { log.error("Failed to create user: {}", email, e); throw e; } } }. Lombok shortcut: @Slf4j annotation generates the log field automatically. Log levels (lowest to highest): TRACE, DEBUG, INFO (default), WARN, ERROR. Configuration in application.properties: logging.level.root=WARN logging.level.com.example=DEBUG logging.level.org.springframework.web=INFO logging.file.name=app.log logging.file.path=/var/log/app logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n. Logback configuration (logback-spring.xml): for advanced configuration — rolling policies, appenders, filters. Use logback-spring.xml (not logback.xml) to use Spring Boot's extensions including profile-specific config. Structured logging: use logstash-logback-encoder for JSON logs in production. Log4j2: exclude logback, add log4j2 starter for alternative implementation.
16
What is @Valid and Bean Validation in Spring Boot?
Bean Validation (JSR-380) with Hibernate Validator provides declarative validation for Java beans. Spring Boot integrates it with spring-boot-starter-validation. Constraint annotations on entity/DTO fields: public class CreateUserRequest { @NotBlank(message = "Name is required") @Size(min = 2, max = 50) private String name; @NotBlank @Email(message = "Invalid email format") private String email; @NotNull @Min(18) @Max(120) private Integer age; @NotNull @Pattern(regexp = "^\d{10}$", message = "Must be 10 digits") private String phone; @Future private LocalDate expiryDate; @NotEmpty private List<@Valid AddressDTO> addresses; }. Triggering validation: add @Valid or @Validated to controller parameters: @PostMapping public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request) { ... }. Spring automatically validates and returns 400 with error details if validation fails. Handling validation errors: @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String,String>> handleValidation(MethodArgumentNotValidException ex) { Map<String,String> errors = new HashMap<>(); ex.getBindingResult().getFieldErrors().forEach(e -> errors.put(e.getField(), e.getDefaultMessage())); return ResponseEntity.badRequest().body(errors); }. Custom validators: implement ConstraintValidator interface for custom business rules. Groups: validate different constraints for different scenarios (Create group vs Update group) using validation groups.
17
What is the @Entity annotation and JPA basics?
JPA (Java Persistence API) is the standard specification for ORM (Object-Relational Mapping) in Java. Hibernate is the most common implementation. Core annotations: @Entity — marks a class as a JPA entity (maps to a DB table); @Table(name = "users") — specify table name (optional if same as class name); @Id — marks the primary key field; @GeneratedValue(strategy = GenerationType.IDENTITY) — auto-generate primary key (IDENTITY uses DB auto-increment, SEQUENCE uses DB sequence, AUTO lets JPA decide); @Column(name = "email_address", nullable = false, unique = true, length = 255) — map to a column with constraints; @Transient — field NOT persisted to DB; @Enumerated(EnumType.STRING) — store enum as string (not ordinal). Example entity: @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; @Column(unique = true, nullable = false) private String email; @Enumerated(EnumType.STRING) private UserStatus status = UserStatus.ACTIVE; @CreatedDate @Column(updatable = false) private LocalDateTime createdAt; @LastModifiedDate private LocalDateTime updatedAt; }. Relationships: @OneToOne, @OneToMany, @ManyToOne, @ManyToMany. Cascade: @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) — operations propagate to children. Fetch types: LAZY (default for @OneToMany, @ManyToMany) vs EAGER (default for @ManyToOne, @OneToOne).
18
What is Spring Boot exception handling?
Spring Boot provides several mechanisms for centralizing exception handling in REST APIs: @ControllerAdvice / @RestControllerAdvice: a global exception handler that applies to all controllers: @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex, HttpServletRequest req) { ErrorResponse error = new ErrorResponse(404, ex.getMessage(), req.getRequestURI(), Instant.now()); return ResponseEntity.status(404).body(error); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ValidationErrorResponse> handleValidation(MethodArgumentNotValidException ex) { Map<String,String> errors = new LinkedHashMap<>(); ex.getBindingResult().getFieldErrors().forEach(e -> errors.put(e.getField(), e.getDefaultMessage())); return ResponseEntity.badRequest().body(new ValidationErrorResponse(errors)); } @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleAll(Exception ex, HttpServletRequest req) { log.error("Unhandled exception", ex); ErrorResponse error = new ErrorResponse(500, "Internal server error", req.getRequestURI(), Instant.now()); return ResponseEntity.status(500).body(error); } }. Custom exceptions: public class ResourceNotFoundException extends RuntimeException { public ResourceNotFoundException(String message) { super(message); } }. @ResponseStatus on exception class: @ResponseStatus(HttpStatus.NOT_FOUND) public class NotFoundException extends RuntimeException. Problem Details (RFC 7807): Spring Boot 3+ supports ProblemDetail response format natively: return ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, "User not found").
19
What is @Transactional in Spring?
@Transactional is Spring's declarative transaction management annotation. When applied to a method or class, Spring wraps the execution in a database transaction — if the method completes successfully, the transaction is committed; if a RuntimeException is thrown, the transaction is rolled back. Usage: @Service public class TransferService { @Transactional public void transfer(Long fromId, Long toId, BigDecimal amount) { Account from = accountRepository.findById(fromId).orElseThrow(); Account to = accountRepository.findById(toId).orElseThrow(); from.debit(amount); to.credit(amount); accountRepository.save(from); accountRepository.save(to); // If any line throws a RuntimeException, entire transfer is rolled back } }. Key attributes: readOnly = true — optimization for read-only methods (disables dirty checking); rollbackFor = {CheckedException.class} — also rollback for checked exceptions (default: only RuntimeException); noRollbackFor = {BusinessException.class}; timeout = 30 — transaction timeout in seconds; propagation — behavior when a transaction already exists: REQUIRED (default — join existing or create new), REQUIRES_NEW (always create new, suspend outer), SUPPORTS, MANDATORY, NEVER, NOT_SUPPORTED, NESTED; isolation — transaction isolation level. Important: @Transactional only works when called externally (via Spring's proxy). Self-invocation (calling a @Transactional method from within the same class) bypasses the proxy. Spring Data JPA repositories: all CrudRepository/JpaRepository methods are @Transactional by default.
20
What is the embedded server in Spring Boot?
Spring Boot includes an embedded servlet container — a fully configured web server bundled within the application JAR. No need to install or configure an external server. Default: Apache Tomcat. The spring-boot-starter-web includes spring-boot-starter-tomcat. The application runs as a standalone JAR: java -jar myapp.jar. Available embedded servers: Tomcat (default), Jetty (lightweight, good for long-lived connections), Undertow (high-performance, Wildfly's server), Netty (for reactive WebFlux applications). Switching to Jetty: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions><exclusion><groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId></dependency>. Configuration: server.port=8080 server.servlet.context-path=/api server.tomcat.max-threads=200 server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=secret server.compression.enabled=true. Programmatic configuration: implement WebServerFactoryCustomizer<TomcatServletWebServerFactory> for advanced Tomcat configuration. WAR deployment: extend SpringBootServletInitializer and package as WAR if deploying to external server — but JAR with embedded server is the standard.
21
What is Spring Boot DevTools?
Spring Boot DevTools provides developer-friendly features that improve the development experience without affecting production behavior. Add: spring-boot-devtools as a optional or test scope dependency — excluded from production JAR automatically. Key features: (1) Automatic restart: monitors classpath for changes (typically after Maven/Gradle build or IDE save). When a class changes, Spring restarts the application in ~1-2 seconds (much faster than a cold start). DevTools uses two classloaders: one for unchanging dependencies, one for application code — only the application classloader restarts; (2) LiveReload: includes an embedded LiveReload server. Browser extensions automatically refresh the browser when resources (templates, CSS, JavaScript) change; (3) Disabled caching: DevTools disables template engine caching (Thymeleaf, FreeMarker), so changes are reflected immediately without restart. Example: spring.thymeleaf.cache=false is set automatically; (4) H2 console: enables H2 web console automatically when H2 is on the classpath and Spring Security is not; (5) Remote DevTools: enables remote application restart over HTTP (for remote debugging — less commonly used); (6) Global settings: ~/.config/spring-boot/spring-boot-devtools.properties for user-level dev settings. Configuration: specify which paths to watch: spring.devtools.restart.additional-paths=.. Exclude paths: spring.devtools.restart.exclude=static/**,public/**.
22
What is spring.datasource configuration?
Spring Boot auto-configures a DataSource when a database driver and spring-boot-starter-data-jpa or spring-boot-starter-jdbc are on the classpath. Configuration properties: spring.datasource.url=jdbc:postgresql://localhost:5432/mydb spring.datasource.username=postgres spring.datasource.password=secret spring.datasource.driver-class-name=org.postgresql.Driver. Spring Boot auto-detects the driver from the URL in most cases. Connection pool (HikariCP — default): Spring Boot uses HikariCP by default (fastest connection pool for Java). spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.idle-timeout=600000 spring.datasource.hikari.max-lifetime=1800000. Multiple datasources: define primary and secondary DataSource beans explicitly with @Primary and @Qualifier. JPA properties: spring.jpa.hibernate.ddl-auto=validate # or: create, create-drop, update, none spring.jpa.show-sql=true # Log SQL statements spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect. ddl-auto values: none — do nothing; validate — validate schema matches entities (recommended for production); update — update schema (risky in production); create — drop and create; create-drop — create on start, drop on close (for testing). Flyway/Liquibase: use database migration tools instead of ddl-auto for production schema management.
23
What is @Configuration and @Bean in Spring Boot?
@Configuration marks a class as a source of bean definitions — Java-based configuration replacing XML beans. @Bean marks a method as a bean factory — the returned object is registered as a Spring bean. @Configuration public class AppConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); } @Bean @Primary public ObjectMapper objectMapper() { return JsonMapper.builder().addModule(new JavaTimeModule()).disable(WRITE_DATES_AS_TIMESTAMPS).build(); } @Bean public RestTemplate restTemplate(RestTemplateBuilder builder) { return builder.setConnectTimeout(Duration.ofSeconds(5)).setReadTimeout(Duration.ofSeconds(10)).build(); } @Bean @ConditionalOnProperty("app.feature.email", havingValue = "true") public EmailService emailService() { return new SmtpEmailService(); } @Bean @Scope("prototype") public JobProcessor jobProcessor() { return new JobProcessor(); // new instance each time } }. Method injection between @Bean methods: @Configuration is CGLib-proxied — calling another @Bean method within the config class returns the Spring-managed singleton, not a new instance: @Bean public ServiceA serviceA() { return new ServiceA(serviceB()); } @Bean public ServiceB serviceB() { return new ServiceB(); }. serviceA and anything else that calls serviceB() gets the same singleton. @Configuration vs @Component: both define beans, but @Configuration is CGLib-proxied for inter-bean calls; @Component is not. Use @Configuration for bean factory classes.
24
What is Spring Boot testing with @SpringBootTest?
Spring Boot provides comprehensive testing support. Key annotations: @SpringBootTest: loads the full application context — integration tests. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles("test") class UserControllerIntegrationTest { @Autowired private TestRestTemplate restTemplate; @Test void shouldCreateUser() { CreateUserRequest req = new CreateUserRequest("Alice", "alice@example.com"); ResponseEntity<User> resp = restTemplate.postForEntity("/api/users", req, User.class); assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED); assertThat(resp.getBody().getEmail()).isEqualTo("alice@example.com"); } }. @WebMvcTest: loads only MVC layer (controller, filters, security — no services or repositories). Faster than @SpringBootTest. Mock services: @WebMvcTest(UserController.class) class UserControllerTest { @Autowired MockMvc mockMvc; @MockBean UserService userService; @Test void shouldReturnUsers() throws Exception { when(userService.findAll()).thenReturn(List.of(new User("Alice"))); mockMvc.perform(get("/api/users")).andExpect(status().isOk()).andExpect(jsonPath("$[0].name").value("Alice")); } }. @DataJpaTest: loads only JPA layer (repositories, entities). Uses in-memory H2 by default. @MockBean: creates a Mockito mock and registers it in the Spring context. @SpyBean: wraps a real Spring bean with Mockito spy. AssertJ for fluent assertions. Testcontainers for integration tests with real databases.
25
What is Spring Security basics?
Spring Security is a powerful, highly customizable framework for authentication and authorization in Spring applications. Core concepts: (1) Authentication: verifying identity (who are you?); (2) Authorization: determining access (what can you do?). Adding Spring Security: add spring-boot-starter-security → immediately secures all endpoints with form-based login. Default user: "user", password: logged at startup. SecurityFilterChain (Spring Security 5.7+): @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/public/**").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) .sessionManagement(s -> s.sessionCreationPolicy(STATELESS)) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) .csrf(csrf -> csrf.disable()); // Disable for REST APIs using JWT return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authManager(AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); } }. UserDetailsService: implement to load users from the database: @Service public class CustomUserDetailsService implements UserDetailsService { public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { User user = userRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("User not found: " + email)); return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), getAuthorities(user)); } }.
26
What is @Component vs @Service vs @Repository?
All three annotations make a class a Spring-managed bean discovered during component scanning — from Spring's perspective, they are functionally equivalent (all result in a singleton bean in the context). The differences are: @Component: generic stereotype for any Spring-managed component. Use when no specific role applies — utility classes, adapter classes, helpers. @Service: semantically indicates a service layer class — business logic, use cases, orchestration. No additional behavior beyond @Component, but communicates intent to developers and tools. Marks the "application/domain layer." @Repository: semantically indicates a data access layer class. Adds exception translation behavior: Spring adds a PersistenceExceptionTranslationPostProcessor that catches provider-specific exceptions (JdbcSQLException, HibernateException) and translates them to Spring's DataAccessException hierarchy. This makes the exception handling consistent regardless of the underlying ORM/data store. Spring Data repository interfaces (JpaRepository) already include this behavior. Custom JDBC repositories should use @Repository to get translation. Why use the specific stereotypes even if functionally the same? (1) Semantic clarity — documentation of intent; (2) Better Spring tool support (structure analysis); (3) @Repository's exception translation; (4) AOP pointcuts can target specific layers: @Pointcut("within(@org.springframework.stereotype.Service *)"). Best practice: always use the most specific stereotype annotation for your class's role.
Practical knowledge for developers with hands-on experience.
01
What is Spring AOP (Aspect-Oriented Programming)?
AOP (Aspect-Oriented Programming) is a programming paradigm that separates cross-cutting concerns (logging, security, transactions, caching) from core business logic. Spring AOP uses dynamic proxies or CGLib to intercept method calls. Core concepts: Aspect: a module encapsulating cross-cutting concern (e.g., logging aspect); Join Point: a point in program execution where an aspect can be applied — in Spring AOP, always a method execution; Advice: action taken at a join point: @Before, @After, @AfterReturning, @AfterThrowing, @Around; Pointcut: expression selecting join points where advice is applied; Weaving: linking aspects to objects. Example — logging aspect: @Aspect @Component public class LoggingAspect { private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class); @Around("execution(* com.example.service.*.*(..))") public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); try { Object result = pjp.proceed(); // execute the method log.info("{} executed in {}ms", pjp.getSignature(), System.currentTimeMillis() - start); return result; } catch (Throwable t) { log.error("Exception in {}: {}", pjp.getSignature(), t.getMessage()); throw t; } } @AfterThrowing(pointcut = "within(@org.springframework.stereotype.Service *)", throwing = "ex") public void logException(JoinPoint jp, Exception ex) { log.error("Service exception at {}: {}", jp.getSignature(), ex.getMessage()); } }. @EnableAspectJAutoProxy: enable AOP (auto-enabled by Spring Boot). Common uses: @Transactional, @Cacheable, @Async, @Secured, method-level logging, performance monitoring.
02
What is Spring Boot caching with @Cacheable?
Spring Boot's caching abstraction provides declarative caching support with multiple backend options. Add: spring-boot-starter-cache. Enable: @EnableCaching on @Configuration. Core annotations: @Cacheable("users") — cache the return value. On subsequent calls with the same parameters, returns cached value without executing the method. Key defaults to method parameters: @Cacheable(value = "users", key = "#id") public User getUserById(Long id) { return userRepository.findById(id).orElseThrow(); }. @CachePut(value = "users", key = "#result.id") — update the cache with the returned value (always executes the method). @CacheEvict(value = "users", key = "#id") — remove from cache. @CacheEvict(value = "users", allEntries = true) — clear the entire cache. @Caching — combine multiple cache operations on one method. Cache providers: Simple (default — ConcurrentHashMap), EhCache, Caffeine (in-memory, high performance), Redis (distributed cache). Redis cache config: add spring-boot-starter-data-redis → Spring Boot auto-configures Redis as cache backend. Customize: @Bean public CacheManager cacheManager(RedisConnectionFactory rcf) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(30)); return RedisCacheManager.builder(rcf).cacheDefaults(config).build(); }. Condition: @Cacheable(condition = "#id > 0", unless = "#result == null") — conditional caching. SpEL in key: key = "#user.id + ':'+ #user.version".
03
What is Spring Data JPA query methods and JPQL?
Spring Data JPA provides multiple ways to define data access queries: 1. Derived query methods (from method name): Spring Data parses the method name and generates the JPQL query: List<User> findByLastNameAndFirstName(String lastName, String firstName); List<User> findByAgeBetween(int min, int max); List<User> findByEmailContainingIgnoreCase(String keyword); List<User> findTop5ByOrderByCreatedAtDesc(); Optional<User> findFirstByEmailOrderByIdDesc(String email); boolean existsByEmail(String email); long countByStatus(String status);. Keywords: findBy, readBy, getBy, countBy, existsBy, deleteBy, And, Or, Not, Like, Containing, StartingWith, EndingWith, Between, LessThan, GreaterThan, OrderBy, Top, First. 2. @Query with JPQL: JPQL uses entity class names and field names (not table/column): @Query("SELECT u FROM User u WHERE u.email = :email AND u.status = :status") Optional<User> findActiveByEmail(@Param("email") String email, @Param("status") String status); @Query("SELECT u FROM User u WHERE SIZE(u.orders) > :minOrders") List<User> findUsersWithManyOrders(@Param("minOrders") int min);. 3. @Query with native SQL: @Query(value = "SELECT * FROM users WHERE full_text_search(?) > 0", nativeQuery = true) List<User> searchUsers(String term);. 4. @Modifying: for UPDATE/DELETE queries: @Modifying @Transactional @Query("UPDATE User u SET u.lastLogin = CURRENT_TIMESTAMP WHERE u.id = :id") int updateLastLogin(@Param("id") Long id);. 5. Projections: return partial data as interface or DTO: interface UserNameEmail { String getName(); String getEmail(); } List<UserNameEmail> findByStatus(String status);. 6. Specification: dynamic queries with Criteria API.
04
What is Spring Boot REST API best practices?
Best practices for Spring Boot REST APIs: 1. URL design: use nouns, not verbs: /users not /getUsers; use plural: /users/1 not /user/1; hierarchical for relationships: /users/1/orders/5. 2. HTTP status codes: 200 OK (success), 201 Created (POST success), 204 No Content (DELETE, empty response), 400 Bad Request (validation error), 401 Unauthorized (missing auth), 403 Forbidden (insufficient permission), 404 Not Found, 409 Conflict (duplicate), 422 Unprocessable Entity (semantic error), 500 Internal Server Error. 3. Request/response DTOs: never expose JPA entities directly — use DTOs to control what's exposed: record CreateUserRequest(String name, String email) {} record UserResponse(Long id, String name, String email, Instant createdAt) {} @PostMapping public ResponseEntity<UserResponse> create(@Valid @RequestBody CreateUserRequest req) { User user = userService.create(req); return ResponseEntity.status(201).body(mapper.toResponse(user)); }. 4. Consistent error response structure: { "status": 400, "error": "Validation failed", "message": "Name is required", "timestamp": "2024-01-15T10:00:00Z", "path": "/api/users" }. 5. Versioning: URI versioning (/api/v1/users), header versioning (Accept: application/vnd.api.v1+json), or query param (?version=1). 6. Pagination: return page metadata: { "data": [...], "page": 0, "size": 20, "totalElements": 500, "totalPages": 25 }. 7. Idempotency keys: for POST requests that should be idempotent. 8. HATEOAS: Spring HATEOAS for hypermedia links.
05
What is Spring Boot JWT authentication implementation?
Implementing JWT authentication in Spring Boot: Dependencies: spring-boot-starter-security + io.jsonwebtoken:jjwt-api, jjwt-impl, jjwt-jackson. JWT utility class: @Component public class JwtUtil { @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration:86400}") private Long expiration; public String generateToken(UserDetails userDetails) { return Jwts.builder().setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)).signWith(getSignKey()).compact(); } public String extractUsername(String token) { return extractClaim(token, Claims::getSubject); } public boolean validateToken(String token, UserDetails userDetails) { return extractUsername(token).equals(userDetails.getUsername()) && !isTokenExpired(token); } private Key getSignKey() { return Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret)); } }. JWT filter: @Component public class JwtAuthFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException { String header = req.getHeader("Authorization"); if (header != null && header.startsWith("Bearer ")) { String token = header.substring(7); String username = jwtUtil.extractUsername(token); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails user = userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(token, user)) { UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(auth); } } } chain.doFilter(req, resp); } }. Register filter in SecurityFilterChain: .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class). Login endpoint: authenticate with AuthenticationManager, generate and return JWT token.
06
What is Spring Boot with Docker?
Containerizing Spring Boot applications with Docker: Simple Dockerfile: FROM eclipse-temurin:21-jre-alpine WORKDIR /app COPY target/myapp.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]. Optimized multi-stage Dockerfile: FROM maven:3.9-eclipse-temurin-21 AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests FROM eclipse-temurin:21-jre-alpine WORKDIR /app COPY --from=builder /build/target/*.jar app.jar EXPOSE 8080 USER nonroot:nonroot ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]. Layered JARs (Spring Boot 2.3+): Spring Boot creates layered JARs for better Docker layer caching (dependencies rarely change, application code changes often): FROM eclipse-temurin:21-jre-alpine AS builder WORKDIR /app COPY target/*.jar app.jar RUN java -Djarmode=layertools -jar app.jar extract FROM eclipse-temurin:21-jre-alpine WORKDIR /app COPY --from=builder /app/dependencies/ ./ COPY --from=builder /app/spring-boot-loader/ ./ COPY --from=builder /app/snapshot-dependencies/ ./ COPY --from=builder /app/application/ ./ ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]. Spring Boot Maven plugin (Buildpacks): mvn spring-boot:build-image -Dspring-boot.build-image.imageName=myapp:1.0 — builds OCI image without Dockerfile using Cloud Native Buildpacks. Environment configuration: pass env vars: docker run -e SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/prod -e SPRING_PROFILES_ACTIVE=prod myapp:1.0. Health checks in docker-compose: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] interval: 30s timeout: 10s retries: 3.
07
What is Spring Cloud and its relationship to Spring Boot?
Spring Cloud is an umbrella project providing a set of tools for building distributed systems and microservices on top of Spring Boot. Each Spring Cloud module addresses a specific distributed systems pattern. Key Spring Cloud components: (1) Spring Cloud Netflix (legacy): Eureka (service registry/discovery), Ribbon (client-side load balancing — deprecated), Hystrix (circuit breaker — deprecated); (2) Spring Cloud OpenFeign: declarative REST client: @FeignClient(name = "payment-service") interface PaymentClient { @PostMapping("/payments") Payment createPayment(@RequestBody PaymentRequest req); }; (3) Spring Cloud LoadBalancer: Ribbon replacement for client-side load balancing; (4) Spring Cloud Config: centralized configuration server — serves properties from Git, Vault, or filesystem to all microservices; (5) Spring Cloud Gateway: API gateway built on Spring WebFlux — routing, filtering, rate limiting; (6) Spring Cloud Sleuth (now Micrometer Tracing): distributed tracing with correlation IDs across services; (7) Spring Cloud Stream: messaging abstraction over Kafka, RabbitMQ — publish/subscribe; (8) Resilience4j: circuit breaker, retry, rate limiter, bulkhead (replaced Hystrix): @CircuitBreaker(name = "paymentService", fallbackMethod = "paymentFallback"); (9) Spring Cloud Contract: consumer-driven contract testing between microservices. Service discovery with Eureka: services register themselves; clients discover service instances by name instead of hardcoded URLs.
08
What is Spring WebFlux and reactive programming?
Spring WebFlux is Spring's reactive web framework introduced in Spring 5, built on Project Reactor and Netty. It supports asynchronous, non-blocking request handling — critical for high concurrency with limited threads. vs Spring MVC: Spring MVC uses blocking I/O (one thread per request); WebFlux uses event-loop model (few threads, non-blocking). WebFlux shines when: making many concurrent external API calls, handling real-time data, WebSocket streams. Core reactive types: Mono<T> — 0 or 1 asynchronous element (like CompletableFuture); Flux<T> — 0 to N asynchronous elements (like a stream). Reactive controller: @RestController @RequestMapping("/api/users") public class UserController { @GetMapping("/{id}") public Mono<User> getUser(@PathVariable Long id) { return userRepository.findById(id); } @GetMapping public Flux<User> getAllUsers() { return userRepository.findAll(); } @PostMapping public Mono<ResponseEntity<User>> createUser(@RequestBody Mono<User> userMono) { return userMono.flatMap(userRepository::save).map(u -> ResponseEntity.status(201).body(u)); } }. Reactive repositories: extend ReactiveCrudRepository or ReactiveMongoRepository (MongoDB natively reactive). Spring Data R2DBC for reactive SQL databases. WebClient (reactive HTTP client): replaces RestTemplate: WebClient.create().get().uri("https://api.example.com/data").retrieve().bodyToMono(Data.class).subscribe(data -> process(data));. When NOT to use WebFlux: CPU-intensive work, blocking libraries (JDBC), simple CRUD — Spring MVC is simpler and performs similarly.
09
What is Spring Boot Flyway/Liquibase database migration?
Database migration tools manage schema changes version-controlled, similar to VCS for database structure. Never use spring.jpa.hibernate.ddl-auto=update in production — use Flyway or Liquibase instead. Flyway (simpler — SQL migrations): add spring-boot-starter-flyway or flyway-core. Place migration files in src/main/resources/db/migration/. File naming: V{version}__{description}.sql: V1__Create_users_table.sql V2__Add_email_index.sql V3__Add_user_roles.sql. Spring Boot auto-runs Flyway on startup. Flyway tracks applied migrations in flyway_schema_history table. flyway.baseline-on-migrate=true for existing databases. Commands: mvn flyway:migrate, flyway:validate, flyway:repair. Configuration: spring.flyway.locations=classpath:db/migration spring.flyway.baseline-on-migrate=true spring.flyway.out-of-order=false. Liquibase (more flexible — XML/YAML/JSON/SQL changesets): add liquibase-core. Place db/changelog/db.changelog-master.yaml: databaseChangeLog: - include: file: db/changelog/001-create-users.yaml - include: file: db/changelog/002-add-email-index.yaml. Each changeset has an ID and author. Liquibase tracks in databasechangelog table. Best practices: never modify applied migrations; create new migration for every change; run in CI/CD; test migrations against production-like data; rollback scripts for Flyway Pro/Liquibase.
10
What is Spring Boot @Async and thread management?
@Async makes Spring execute a method asynchronously in a separate thread, returning immediately to the caller. Enable: @EnableAsync on @Configuration. Usage: @Async public CompletableFuture<User> findUserAsync(Long id) { // Runs in separate thread return CompletableFuture.completedFuture(userRepository.findById(id).orElseThrow()); } @Async public void sendEmailAsync(String to, String subject) { // Fire and forget // emailService.send(to, subject); } // Calling async method: CompletableFuture<User> future = userService.findUserAsync(1L); User user = future.get(); // blocks until complete, or: future.thenAccept(u -> log.info("Found: {}", u.getName()));. Custom thread pool: by default, uses SimpleAsyncTaskExecutor (creates a new thread per task). Configure a proper pool: @Bean(name = "taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(20); executor.setQueueCapacity(100); executor.setThreadNamePrefix("Async-"); executor.setRejectedExecutionHandler(new CallerRunsPolicy()); executor.initialize(); return executor; } @Async("taskExecutor") // specify the executor. Exception handling in @Async: exceptions in void methods are lost. Use CompletableFuture and handle exceptions on the caller side, or implement AsyncUncaughtExceptionHandler. Limitations: @Async only works when called from a different Spring bean (same class = no proxy). @Async methods must be public. Common use cases: sending emails, notifications, generating reports, long-running background tasks, parallel external API calls.
11
What is Spring Boot testing strategies?
Spring Boot testing pyramid: 1. Unit tests (no Spring context): test individual classes in isolation using Mockito. No Spring overhead: @ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock UserRepository userRepository; @InjectMocks UserService userService; @Test void shouldCreateUser() { when(userRepository.save(any())).thenReturn(new User("Alice", "alice@example.com")); User result = userService.create("Alice", "alice@example.com"); assertThat(result.getName()).isEqualTo("Alice"); verify(userRepository).save(argThat(u -> u.getEmail().equals("alice@example.com"))); } }. 2. Slice tests (partial Spring context): @WebMvcTest (controller + MockMvc), @DataJpaTest (JPA layer only, H2), @DataMongoTest, @JsonTest (Jackson serialization only). Much faster than full context. 3. Integration tests (full context): @SpringBootTest loads everything. Use Testcontainers for real databases: @SpringBootTest @Testcontainers class OrderIntegrationTest { @Container static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15"); @DynamicPropertySource static void registerProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgres::getJdbcUrl); } @Test void shouldCreateOrder() { ... } }. 4. MockMvc for controller tests: mockMvc.perform(post("/api/users").contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(request))).andExpect(status().isCreated()).andExpect(jsonPath("$.email").value("alice@example.com"));. Best practices: test behavior not implementation; prefer @DataJpaTest over mocking repository; use @MockBean sparingly; test error scenarios and edge cases.
12
What is Spring Boot Actuator for production monitoring?
Spring Boot Actuator + Micrometer provides comprehensive production monitoring: Micrometer metrics integration: Actuator uses Micrometer (vendor-neutral metrics facade) to export metrics to Prometheus, Datadog, CloudWatch, InfluxDB, etc. Prometheus + Grafana setup: add micrometer-registry-prometheus dependency → /actuator/prometheus endpoint exposes Prometheus-formatted metrics. Prometheus scrapes this endpoint; Grafana visualizes. Custom metrics: @Component public class OrderMetrics { private final Counter orderCreatedCounter; private final Timer orderProcessingTimer; public OrderMetrics(MeterRegistry registry) { orderCreatedCounter = registry.counter("orders.created", "type", "standard"); orderProcessingTimer = registry.timer("orders.processing.time"); } public void recordOrderCreated() { orderCreatedCounter.increment(); } public void recordProcessingTime(Supplier<Order> processOrder) { orderProcessingTimer.record(processOrder); } }. Custom health indicators: @Component public class DatabaseHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Health.Builder builder) { // Check external DB connection builder.up().withDetail("database", "PostgreSQL").withDetail("version", "15.0"); } }. Health groups: management.endpoint.health.group.readiness.include=db,redis — Kubernetes readiness probe uses /actuator/health/readiness. Liveness vs Readiness: liveness = is the app alive (not deadlocked); readiness = is it ready to serve traffic (dependencies up). Info endpoint: management.info.git.mode=full — expose git commit hash for deployment verification.
13
What is Spring Boot microservices patterns?
Common microservices patterns with Spring Boot: 1. API Gateway: Spring Cloud Gateway as the entry point — routing, authentication, rate limiting, request transformation. 2. Service Registry/Discovery: Eureka Server: @EnableEurekaServer; clients register with @EnableDiscoveryClient. 3. Circuit Breaker with Resilience4j: @CircuitBreaker(name = "paymentService", fallbackMethod = "fallback") @Retry(name = "paymentService") @TimeLimiter(name = "paymentService") public CompletableFuture<Payment> processPayment(PaymentRequest req) { return CompletableFuture.supplyAsync(() -> paymentClient.process(req)); } private CompletableFuture<Payment> fallback(PaymentRequest req, Exception e) { return CompletableFuture.completedFuture(Payment.pending(req)); }. 4. Saga Pattern: orchestration-based sagas using Spring State Machine or Temporal; choreography via Kafka events. 5. CQRS: separate read models (optimized for queries) from write models (command handlers) — Axon Framework for event sourcing. 6. Distributed Tracing: Micrometer Tracing + Zipkin/Jaeger — spring.zipkin.base-url=http://zipkin:9411. Trace IDs propagated via HTTP headers. 7. Event-driven with Kafka: @KafkaListener(topics = "orders") public void handleOrder(OrderEvent event) { ... } kafkaTemplate.send("payments", PaymentEvent.from(order));. 8. Config Server: centralized configuration; spring.config.import=configserver:http://config-server:8888. 9. Health checks for K8s: liveness: /actuator/health/liveness; readiness: /actuator/health/readiness.
Deep expertise questions for senior and lead roles.
01
What is Spring Boot auto-configuration internals?
Understanding Spring Boot auto-configuration deeply: AutoConfiguration loading mechanism (Spring Boot 3.x): AutoConfigurationImportSelector implements ImportSelector. When @EnableAutoConfiguration is processed, Spring invokes getAutoConfigurationEntry() which reads all auto-configuration class names from META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. These are filtered by @Conditional annotations. AutoConfiguration ordering: @AutoConfiguration(after = DataSourceAutoConfiguration.class) ensures correct ordering — JPA config activates after DataSource config. @AutoConfiguration(before = WebMvcAutoConfiguration.class) for earlier activation. Creating custom auto-configuration: (1) Create @AutoConfiguration @ConditionalOnClass(MyLibrary.class) public class MyLibraryAutoConfiguration { @Bean @ConditionalOnMissingBean public MyLibraryService myLibraryService() { return new MyLibraryService(); } }; (2) Register in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: com.example.MyLibraryAutoConfiguration. Debugging auto-configuration: start with --debug → ConditionEvaluationReport printed. Or ConditionEvaluationReportLoggingListener. @Conditional variants: @ConditionalOnClass/@ConditionalOnMissingClass (classpath presence), @ConditionalOnBean/@ConditionalOnMissingBean (bean presence), @ConditionalOnProperty (property value), @ConditionalOnWebApplication/@ConditionalOnNotWebApplication, @ConditionalOnExpression (SpEL), @ConditionalOnResource (resource exists), @ConditionalOnSingleCandidate (exactly one qualifying bean). Order matters: @ConditionalOnMissingBean checks happen after all @Bean methods in @Configuration classes are processed — auto-configuration "gives up" if user defined their own bean.
02
What is Spring Security OAuth2 and JWT implementation?
Spring Security 6 OAuth2 Resource Server with JWT: Dependencies: spring-boot-starter-security + spring-boot-starter-oauth2-resource-server. Resource server configuration: @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthConverter()))); http.authorizeHttpRequests(auth -> auth.requestMatchers("/api/public/**").permitAll().requestMatchers("/api/admin/**").hasAuthority("SCOPE_admin").anyRequest().authenticated()); return http.build(); }. JWT configuration: spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://auth-server/.well-known/jwks.json — validates JWT signatures using the auth server's public keys. Or for symmetric signing: spring.security.oauth2.resourceserver.jwt.secret=mySecretKey. Custom JWT converter (extract roles/claims): @Bean public JwtAuthenticationConverter jwtAuthConverter() { JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter(); converter.setAuthoritiesClaimName("roles"); converter.setAuthorityPrefix("ROLE_"); JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter(); jwtConverter.setJwtGrantedAuthoritiesConverter(converter); return jwtConverter; }. Authorization Server (Spring Authorization Server): Spring's own OAuth2 authorization server implementation: @Import(OAuth2AuthorizationServerConfiguration.class) — provides /oauth2/token, /oauth2/authorize, /oauth2/jwks endpoints. Register clients, configure token settings, customize claims. Method security: @EnableMethodSecurity @GetMapping @PreAuthorize("hasRole("ADMIN") or #userId == authentication.principal.subject") public User getUser(@PathVariable String userId) { ... }.
03
What is Spring Boot performance optimization?
Spring Boot performance optimization strategies: 1. Startup time: use Spring Boot's lazy initialization: spring.main.lazy-initialization=true — beans created on first request, not at startup. Reduces startup time by 40-60%. Spring Native (GraalVM): compile to native executable — millisecond startup, lower memory. mvn spring-boot:build-image -Pnative. 2. Database performance: use read-only transactions for queries: @Transactional(readOnly = true) — disables dirty checking, reduces lock scope; use projections to fetch only needed columns; enable second-level cache (EhCache/Redis) with Hibernate: @Cache(usage = CacheConcurrencyStrategy.READ_WRITE); use pagination for large result sets; add connection pool tuning (HikariCP). 3. HTTP layer: enable GZIP compression: server.compression.enabled=true; enable HTTP/2: server.http2.enabled=true; configure server thread pools: server.tomcat.max-threads=200. 4. JVM tuning: JAVA_OPTS="-Xms512m -Xmx2048m -XX:+UseG1GC -XX:MaxGCPauseMillis=200". 5. Cache aggressively: @Cacheable with Redis for frequently-accessed, rarely-changed data; cache-aside pattern with manual TTL management. 6. Async processing: @Async with custom thread pools for I/O-bound operations; CompletableFuture.allOf() for parallel external calls. 7. Avoid N+1 queries: use @EntityGraph or JOIN FETCH: @Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.userId = :id") List<Order> findWithItems(@Param("id") Long id);. 8. Virtual threads (Java 21 + Spring Boot 3.2): spring.threads.virtual.enabled=true — enables virtual threads for Tomcat, very high concurrency with minimal overhead.
04
What is Spring Boot with Kubernetes?
Deploying Spring Boot applications on Kubernetes: Actuator for Kubernetes probes: management.endpoint.health.probes.enabled=true management.health.livenessState.enabled=true management.health.readinessState.enabled=true. K8s YAML: livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 20 periodSeconds: 5. Graceful shutdown: server.shutdown=graceful spring.lifecycle.timeout-per-shutdown-phase=30s. K8s terminationGracePeriodSeconds: 60. Resource limits: resources: requests: memory: "512Mi" cpu: "250m" limits: memory: "1Gi" cpu: "500m". ConfigMaps and Secrets: spring.config.import=configtree:/etc/config/ — load from ConfigMap-mounted files: envFrom: - configMapRef: name: app-config - secretRef: name: app-secrets. Horizontal Pod Autoscaler: scale based on CPU: kubectl autoscale deployment myapp --cpu-percent=70 --min=2 --max=10. Spring Boot Actuator's /actuator/metrics exposed to Prometheus enables custom HPA metrics. Spring Cloud Kubernetes: service discovery using Kubernetes API instead of Eureka — auto-discover services by Kubernetes service names. Rolling deployment: strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 — zero-downtime deployments. Startup command with profiles: env: - name: SPRING_PROFILES_ACTIVE value: production - name: JAVA_TOOL_OPTIONS value: "-XX:MaxRAMPercentage=75".
05
What is Spring Boot reactive programming with R2DBC?
R2DBC (Reactive Relational Database Connectivity) is a reactive API for relational databases — enables non-blocking SQL database access, unlike traditional JDBC which blocks threads. Used with Spring WebFlux for fully reactive applications. Dependencies: spring-boot-starter-webflux + spring-boot-starter-data-r2dbc + r2dbc-postgresql (or r2dbc-mysql, r2dbc-h2). Configuration: spring.r2dbc.url=r2dbc:postgresql://localhost:5432/mydb spring.r2dbc.username=postgres spring.r2dbc.password=secret. Entity: @Table("users") public class User { @Id private Long id; private String name; private String email; }. Reactive repository: public interface UserRepository extends ReactiveCrudRepository<User, Long> { Flux<User> findByStatus(String status); Mono<User> findByEmail(String email); @Query("SELECT * FROM users WHERE age BETWEEN :min AND :max") Flux<User> findByAgeRange(@Param("min") int min, @Param("max") int max); }. Reactive service: @Service public class UserService { public Flux<User> findAll() { return userRepository.findAll(); } public Mono<User> create(CreateUserRequest req) { return userRepository.save(new User(req.name(), req.email())); } public Mono<User> findById(Long id) { return userRepository.findById(id).switchIfEmpty(Mono.error(new NotFoundException("User not found"))); } }. Transactions in reactive: @Transactional public Mono<Void> transfer(Long fromId, Long toId, BigDecimal amount) { return userRepository.findById(fromId).flatMap(from -> { from.debit(amount); return userRepository.save(from); }).flatMap(saved -> userRepository.findById(toId)).flatMap(to -> { to.credit(amount); return userRepository.save(to); }).then(); }. Limitation: R2DBC has no JPA/Hibernate support — no lazy loading, no entity relationships automatically handled.
06
What is Spring Boot GraalVM native image compilation?
Spring Boot Native (Spring Boot 3.x with GraalVM) compiles Spring Boot applications to native executables using GraalVM's Ahead-of-Time (AOT) compiler. Benefits: millisecond startup time (vs seconds for JVM), very low memory footprint (100-300MB vs 300-600MB for JVM), no JVM warmup needed. Critical for serverless and FaaS. Challenges: dynamic features (reflection, dynamic proxy, class loading, serialization) don't work without hints. Spring Boot AOT processor generates hints automatically for most Spring features. Build native image: requires GraalVM 22.3+. Maven plugin: mvn spring-boot:build-image -Pnative. Or native compilation directly: mvn native:compile -Pnative. AOT processing: Spring Boot 3 adds an AOT build phase that: processes @Configuration classes at build time, generates bean definitions as generated code (not reflection), generates GraalVM hints for reflection/proxy. Runtime hints: for third-party libraries not Spring-aware: @RegisterReflectionForBinding(MyClass.class) @ImportRuntimeHints(MyRuntimeHints.class) public class AppConfig { ... } class MyRuntimeHints implements RuntimeHintsRegistrar { public void registerHints(RuntimeHints hints, ClassLoader classLoader) { hints.reflection().registerType(MyClass.class, MemberCategory.INVOKE_DECLARED_METHODS); } }. Testing native image: @SpringBootTest @TestClassOrder(ClassOrderer.OrderAnnotation.class) class NativeIntegrationTest { ... } + native build profile. Tradeoffs: longer build times (AOT compilation takes minutes vs seconds), not all libraries supported, debugging harder.