Spring Boot โ Overview & Why It Matters
Spring Boot makes it easy to create stand-alone, production-grade Spring-based applications with minimal configuration. It is the de-facto standard for building Java microservices and web applications.
What Is Spring Boot?โ
Spring Boot is an opinionated framework built on top of the Spring Framework. It eliminates most of the boilerplate configuration that Spring applications traditionally require, letting developers focus on business logic instead of infrastructure plumbing.
Key idea: Convention over configuration โ sensible defaults are provided out of the box, and you only override what you need.
๐ถ Beginner Concept: The "Meal Kit" Analogyโ
If building a backend is like making Lasagna:
- Raw Spring Framework: You go to the grocery store, grab flour, tomatoes, cheese, ground beef, pan, and an oven. You measure everything yourself entirely from scratch. You even build the oven (the Tomcat web server).
- Spring Boot: You sign up for HelloFresh (a meal kit). A box arrives with perfectly measured ingredients, a pre-heated pan, and an oven already running on your counter. You just combine the specific ingredients you want, throw away what you don't, and hit "Bake".
You don't lose any control of the recipe (you can still add your own spices). Spring Boot just assumes you don't want to spend 3 hours building an oven every time you want dinner.
๐ฏ Why Should I Care?โ
For Beginners: From Zero to Running API in 5 Minutesโ
Without Spring Boot, building a simple REST API in Java requires:
- Create a Maven/Gradle project manually
- Add 15+ dependencies (Spring MVC, Jackson, Tomcat, logging, etc.) and manage their version compatibility
- Write an XML configuration file (or multiple Java config classes) for component scanning, view resolvers, message converters
- Configure a
web.xmldeployment descriptor - Set up an external Tomcat server, build a WAR file, deploy it
- Write a
DispatcherServletconfiguration - Then start writing your actual controller
With Spring Boot:
- Go to start.spring.io, check "Spring Web", download
- Write your controller
- Run
./mvnw spring-boot:run
That's it. Everything else is auto-configured.
For Intermediate Developers: The Ecosystem Multiplierโ
Spring Boot isn't just about saving setup time โ it's the gateway to the entire Spring ecosystem:
spring-boot-starter-web โ REST APIs, MVC
spring-boot-starter-data-jpa โ Database access with JPA/Hibernate
spring-boot-starter-security โ Authentication & authorization
spring-boot-starter-actuator โ Production monitoring
spring-boot-starter-cache โ Caching abstraction (Redis, Caffeine)
spring-boot-starter-amqp โ RabbitMQ messaging
spring-boot-starter-webflux โ Reactive programming
spring-cloud-starter-* โ Service discovery, config server, circuit breakers
Each starter is a pre-tested, version-compatible package. You never deal with dependency hell โ Spring Boot's BOM (Bill of Materials) ensures everything works together.
For Senior Engineers: Why Boot Won the Java Marketโ
Spring Boot dominates Java backend development for structural reasons:
| Factor | Impact |
|---|---|
| Fat JAR deployment | Eliminated the WAR/application server complexity that plagued Java EE |
| 12-Factor App alignment | Externalized config, stateless processes, port binding โ cloud-native by design |
| Docker/K8s native | Single java -jar command โ perfect for containers |
| Actuator | Health checks, metrics, and readiness probes built-in โ production-ready from day 1 |
| Auto-configuration | Massively reduced onboarding time for new team members |
| Spring Initializr | Standardized project structure across the industry |
Before Spring Boot (2013), Java web development was losing ground to Node.js, Ruby on Rails, and Django because of setup complexity. Spring Boot reversed that trend entirely.
Why Use Spring Boot?โ
Problems It Solvesโ
| Problem with Raw Spring | How Spring Boot Fixes It |
|---|---|
| Extensive XML or Java configuration | Auto-configuration infers settings from the classpath |
| Manual dependency management | Starter POMs bundle compatible dependencies |
| Embedded server setup is complex | Embedded Tomcat/Jetty/Undertow with zero config |
| Deploying WAR files to external servers | Produces runnable fat JARs |
| No standard project structure | Spring Initializr generates a ready-to-go scaffold |
| Production monitoring is an afterthought | Actuator endpoints included for health, metrics, etc. |
Core Benefitsโ
- Rapid Development โ
spring-boot-starter-*dependencies pull in everything you need. A REST API can be up in minutes. - Auto-Configuration โ
@EnableAutoConfiguration(included in@SpringBootApplication) scans the classpath and configures beans automatically. - Embedded Server โ No need for an external application server. The app starts with
java -jar. - Production-Ready โ Actuator provides health checks, metrics, environment info, and HTTP trace out of the box.
- Opinionated Defaults โ Sensible defaults reduce decision fatigue while remaining fully overridable.
- Microservice-Friendly โ Lightweight, self-contained JARs are ideal for containerized deployments (Docker, Kubernetes).
How Does Spring Boot Help Development?โ
1. Starter Dependenciesโ
Starters are curated dependency descriptors. Instead of hunting for compatible library versions, you declare a single starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
This pulls in Spring MVC, Jackson, embedded Tomcat, and validation โ all in compatible versions managed by the Spring Boot BOM.
Common starters:
| Starter | What It Provides |
|---|---|
spring-boot-starter-web | REST/MVC, embedded Tomcat, Jackson |
spring-boot-starter-data-jpa | JPA, Hibernate, Spring Data |
spring-boot-starter-security | Spring Security defaults |
spring-boot-starter-test | JUnit 5, Mockito, AssertJ, MockMvc |
spring-boot-starter-actuator | Health, metrics, info endpoints |
spring-boot-starter-validation | Bean Validation (Hibernate Validator) |
spring-boot-starter-cache | Cache abstraction |
spring-boot-starter-amqp | RabbitMQ integration |
2. Auto-Configurationโ
Spring Boot examines the classpath at startup and automatically configures beans:
DataSourceif H2/MySQL/PostgreSQL driver is detectedEntityManagerFactoryif JPA is on the classpathDispatcherServletif Spring MVC is presentSecurityFilterChainif Spring Security is present
You can inspect what was auto-configured:
--debug
Or in application.properties:
debug=true
How Auto-Configuration Actually Worksโ
// A simplified view of how DataSource auto-configuration works
@AutoConfiguration
@ConditionalOnClass(DataSource.class) // only if DataSource is on classpath
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean // only if YOU haven't defined your own DataSource
public DataSource dataSource(DataSourceProperties properties) {
return DataSourceBuilder.create()
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword())
.build();
}
}
The key conditional annotations:
| Annotation | Meaning |
|---|---|
@ConditionalOnClass | Only configure if this class exists on the classpath |
@ConditionalOnMissingBean | Only configure if the user hasn't defined their own bean |
@ConditionalOnProperty | Only configure if a specific property is set |
@ConditionalOnWebApplication | Only configure in web applications |
@ConditionalOnBean | Only configure if another specific bean exists |
This is why Spring Boot is "opinionated but flexible": It auto-configures everything, but @ConditionalOnMissingBean means your explicit configuration always wins.
3. Externalized Configurationโ
Spring Boot supports a powerful property resolution order:
- Command-line arguments
SPRING_APPLICATION_JSON(inline JSON)- OS environment variables
application-{profile}.properties/.ymlapplication.properties/.yml@PropertySourceannotations- Default properties
This means the same artifact can run in dev, staging, and production with different configs โ no recompilation needed.
# application-dev.yml
server:
port: 8080
spring:
datasource:
url: jdbc:h2:mem:devdb
# application-prod.yml
server:
port: 443
spring:
datasource:
url: jdbc:postgresql://prod-host:5432/mydb
Type-Safe Configuration with @ConfigurationPropertiesโ
For complex configuration, use type-safe binding instead of scattered @Value annotations:
// โ Fragile โ typos in property names are silent errors
@Value("${app.payment.stripe.api-key}")
private String stripeApiKey;
@Value("${app.payment.stripe.timeout-ms}")
private int timeoutMs;
// โ
Type-safe, validated, and IDE-friendly
@ConfigurationProperties(prefix = "app.payment.stripe")
@Validated
public record StripeProperties(
@NotBlank String apiKey,
@Min(100) @Max(30000) int timeoutMs,
@NotBlank String webhookSecret,
boolean sandboxMode
) {}
// Usage
@Service
public class PaymentService {
private final StripeProperties config;
public PaymentService(StripeProperties config) {
this.config = config;
}
}
app:
payment:
stripe:
api-key: ${STRIPE_API_KEY}
timeout-ms: 5000
webhook-secret: ${STRIPE_WEBHOOK_SECRET}
sandbox-mode: true
4. Spring Boot Actuatorโ
Actuator exposes operational endpoints:
| Endpoint | Purpose |
|---|---|
/actuator/health | Application health status |
/actuator/metrics | JVM, HTTP, and custom metrics |
/actuator/info | Build and application info |
/actuator/env | Environment properties |
/actuator/beans | All registered beans |
/actuator/loggers | View and change log levels at runtime |
/actuator/httptrace | Recent HTTP request/response traces |
Health Checks for Kubernetesโ
Spring Boot Actuator integrates natively with Kubernetes probes:
# application.yml
management:
endpoint:
health:
probes:
enabled: true # exposes /actuator/health/liveness and /actuator/health/readiness
health:
livenessState:
enabled: true
readinessState:
enabled: true
# Kubernetes deployment.yml
containers:
- name: my-app
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
Liveness vs Readiness:
| Probe | Question It Answers | Failure Action |
|---|---|---|
| Liveness | "Is the app still alive, or is it hung/deadlocked?" | Kubernetes restarts the pod |
| Readiness | "Is the app ready to serve traffic?" | Kubernetes stops routing traffic to it |
Custom Health Indicatorsโ
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
private final DataSource dataSource;
@Override
public Health health() {
try (Connection conn = dataSource.getConnection()) {
if (conn.isValid(2)) {
return Health.up()
.withDetail("database", "reachable")
.withDetail("latency", measureLatency())
.build();
}
} catch (SQLException e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
return Health.down().build();
}
}
5. Spring Boot DevToolsโ
spring-boot-devtools accelerates the development loop:
- Automatic restart โ Restarts the app when classes change
- LiveReload โ Triggers browser refresh on resource changes
- Property defaults โ Disables caching in development for instant feedback
- Remote debugging โ Supports remote app restarts and updates
The @SpringBootApplication Annotationโ
This single annotation combines three powerful annotations:
@SpringBootApplication
// Equivalent to:
// @SpringBootConfiguration โ marks this as a configuration class
// @EnableAutoConfiguration โ enables auto-configuration
// @ComponentScan โ scans the current package and sub-packages
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Common Gotcha: Package Structureโ
@ComponentScan scans the current package and sub-packages. If your main class is in com.myapp, Spring will only find beans under com.myapp.*.
โ
Correct structure:
com.myapp/
โโโ MyApplication.java โ @SpringBootApplication here
โโโ controller/
โ โโโ UserController.java โ found by component scan
โโโ service/
โ โโโ UserService.java โ found by component scan
โโโ repository/
โโโ UserRepository.java โ found by component scan
โ Wrong structure:
com.myapp.config/
โโโ MyApplication.java โ @SpringBootApplication here
com.myapp.controller/
โ โโโ UserController.java โ NOT found! Different package tree
Spring Boot vs Spring Framework โ Deep Comparisonโ
| Aspect | Spring Framework | Spring Boot |
|---|---|---|
| Philosophy | Maximum flexibility, zero opinions | Opinionated defaults, overridable |
| Configuration | Manual (XML or Java) | Auto-configuration from classpath |
| Server | External (deploy WAR to Tomcat) | Embedded (Tomcat/Jetty/Undertow in JAR) |
| Dependencies | Manual version management (dependency hell) | Starter POMs with managed BOM |
| Setup Time | Hours to days | Minutes |
| Production Monitoring | Manual integration | Actuator built-in |
| Learning Curve | Steeper (must understand IoC deeply) | Gentler entry point |
| Deployment | WAR file โ application server | Fat JAR โ java -jar app.jar |
| Testing | Complex setup with @ContextConfiguration | @SpringBootTest with auto-slice testing |
| Cloud-Native | Requires significant adaptation | Docker/K8s ready out of the box |
Spring Boot does not replace Spring Framework โ it builds on top of it and removes friction.
What Spring Boot Adds on Top of Springโ
Spring Framework (the foundation):
โโโ IoC Container (ApplicationContext, BeanFactory)
โโโ Dependency Injection (@Autowired, @Qualifier)
โโโ AOP (Aspect-Oriented Programming)
โโโ Spring MVC (DispatcherServlet, Controllers)
โโโ Spring Data (Repository abstraction)
โโโ Spring Security (Authentication, Authorization)
โโโ Transaction Management (@Transactional)
โโโ ... (everything Spring can do)
Spring Boot (the accelerator on top):
โโโ Auto-Configuration (configures all the above automatically)
โโโ Starter Dependencies (curated, compatible packages)
โโโ Embedded Server (no external Tomcat needed)
โโโ Actuator (health, metrics, environment)
โโโ DevTools (hot reload, live reload)
โโโ Externalized Configuration (profiles, YAML, env vars)
โโโ Spring Initializr (project scaffolding)
โโโ Fat JAR packaging (single deployable artifact)
When to Use Plain Spring Without Bootโ
| Scenario | Why |
|---|---|
| Shared library / module | Libraries shouldn't include an embedded server or auto-configuration |
| Legacy application server | Mandated WAR deployment to WebSphere/WebLogic |
| Ultra-lightweight utility | Plain Spring IoC is lighter than Boot's startup overhead |
| Learning | Understanding raw Spring first makes Boot's magic less mysterious |
| Framework development | Building your own framework on top of Spring |
๐ง Senior Deep Dive: The Startup Lifecycle (Under the Hood)โ
When you call SpringApplication.run();, Spring Boot goes through a highly organized sequence of initialization steps. Understanding this is critical for debugging "My Bean isn't loading before X happens" issues.
SpringApplicationInstantiation: Spring determines if this is a web application (Servlet,Reactive, orNone) based on the classpath libraries.- Environment Preparation:
OS environment variables, system properties, and
application.ymlare merged into theEnvironment. - ApplicationContext Creation:
The massive heavy-lifting phase begins. Based on the environment type, it creates either an
AnnotationConfigServletWebServerApplicationContextor similar. - Auto-Configuration Deep Scan:
Spring uses
SpringFactoriesLoaderto checkMETA-INF/spring.factories(ororg.springframework.boot.autoconfigure.AutoConfiguration.importsin modern versions) from all imported dependencies. It tries to initialize thousands of beans wrapped in@ConditionalOnClassor@ConditionalOnMissingBeanboundaries. - Bean Definition Loading:
Your custom
@Componentand@Serviceclasses are scanned into the Bean Registry. Spring resolves all the dependency injection trees. - Embedded Server Started: The Tomcat/Jetty engine is booted, binding to the configured port (e.g., 8080).
- ApplicationReadyEvent Fired:
CommandLineRunnerandApplicationRunnerimplementations are invoked sequentially. The terminal prints theStarted Application in X.XXX secondslog.
Startup Timeline Visualizationโ
Time โ
0ms 200ms 500ms 1500ms 2500ms 3000ms
โ โ โ โ โ โ
โผ โผ โผ โผ โผ โผ
โโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโ
โ Create โ Load โ Auto- โ Create โ Start โ
โ Spring โ Env & โ Configure โ User โ Embedded โ
โ App โ Profiles โ Beans โ Beans โ Server โ
โ โ โ โ โ โ
โ Detect โ Merge โ Resolve โ DI graph โ Bind โ
โ web โ props, โ conditionsโ resolutionโ port โ
โ type โ YAML, โ Load auto โ @Post- โ Ready! โ
โ โ env vars โ configs โ Construct โ โ
โโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโ
โ
ApplicationReadyEvent
CommandLineRunner
ApplicationRunner
Lifecycle hooks:
| Hook | When It Runs | Use Case |
|---|---|---|
CommandLineRunner | After context is ready, receives raw CLI args | Run batch jobs, seed data |
ApplicationRunner | After context is ready, receives parsed ApplicationArguments | Same, with parsed args |
@PostConstruct | After a specific bean is injected, but before the whole context is ready | Initialize a single bean |
@PreDestroy | Shutting down, right before bean is removed from the context | Cleanup resources |
SmartLifecycle | Fine-grained start/stop control with numerical ordering | Ordered startup of components |
ApplicationStartedEvent | After context refresh, before runners | Early post-startup logic |
ApplicationReadyEvent | After all runners complete | Signal "fully ready" |
ContextClosedEvent | Application shutdown begins | Graceful shutdown logic |
Startup Performance Optimizationโ
For production services where startup time matters (serverless, scale-to-zero):
# Lazy initialization โ beans created on first access, not at startup
spring.main.lazy-initialization=true
# Disable unnecessary auto-configurations
spring.autoconfigure.exclude=\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
// GraalVM Native Image โ AOT compilation for instant startup
// Build: mvn -Pnative native:compile
// Result: ~50ms startup instead of ~3000ms
| Technique | Startup Improvement | Trade-off |
|---|---|---|
| Lazy init | 30โ50% faster | First request is slower |
| Exclude unused auto-configs | 10โ20% faster | Manual maintenance |
| Spring AOT (GraalVM Native) | 90%+ faster (~50ms) | Longer build time, reflection limitations |
| Class Data Sharing (CDS) | 20โ30% faster | Requires JDK setup |
| Virtual threads | N/A (not startup) | Improves runtime throughput |
๐ข Real-World Architecture Patternsโ
1. Layered Architecture (Most Common)โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Controller Layer โ @RestController
โ (HTTP handling, request/response DTOs) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Service Layer โ @Service
โ (Business logic, orchestration) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Repository Layer โ @Repository
โ (Data access, database operations) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Database / External APIs โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
private final OrderService orderService;
@PostMapping
public ResponseEntity<OrderResponse> createOrder(@Valid @RequestBody CreateOrderRequest request) {
Order order = orderService.createOrder(request.toCommand());
return ResponseEntity.status(HttpStatus.CREATED).body(OrderResponse.from(order));
}
}
@Service
@Transactional
public class OrderService {
private final OrderRepository orderRepository;
private final PaymentGateway paymentGateway;
private final NotificationService notificationService;
public Order createOrder(CreateOrderCommand command) {
Order order = Order.create(command);
order = orderRepository.save(order);
paymentGateway.charge(order.getPaymentDetails());
notificationService.sendConfirmation(order);
return order;
}
}
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerIdAndStatus(Long customerId, OrderStatus status);
}
2. Hexagonal / Ports & Adapters (Enterprise)โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Driving Adapters โ Driven Adapters โ
โ (Input) โ (Output) โ
โ โ โ
โ REST Controller โโโโโโ โ โโโโโ JPA Repo โ
โ GraphQL API โโโโโโโโโโค โ โโโโโ Redis โ
โ Kafka Consumer โโโโโโโผโโโโถ Domain โโโโโค โ
โ Scheduled Job โโโโโโโโค โ โโโโโ Stripe โ
โ โ โ โโโโโ Email โ
โ (Spring MVC) โ โ (Spring Data) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Port (interface in domain layer)
public interface PaymentPort {
PaymentResult charge(PaymentRequest request);
}
// Adapter (implementation in infrastructure layer)
@Component
@Profile("production")
public class StripePaymentAdapter implements PaymentPort {
private final StripeClient stripeClient;
@Override
public PaymentResult charge(PaymentRequest request) {
// Stripe-specific implementation
}
}
@Component
@Profile("test")
public class FakePaymentAdapter implements PaymentPort {
@Override
public PaymentResult charge(PaymentRequest request) {
return PaymentResult.success(); // always succeeds in tests
}
}
3. Spring Boot + Docker + Kubernetesโ
# Multi-stage build for optimal image size
FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY . .
RUN ./mvnw package -DskipTests
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
# Spring Boot optimizations for containers
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
# application.yml โ container-aware configuration
server:
shutdown: graceful # wait for active requests to complete
spring:
lifecycle:
timeout-per-shutdown-phase: 30s # max wait time for graceful shutdown
management:
server:
port: 9090 # separate port for actuator (not exposed publicly)
โ๏ธ Trade-offs & Common Pitfallsโ
Auto-Configuration Surprisesโ
// โ Problem: You add spring-boot-starter-data-redis to your pom.xml
// just for the Redis client library, but Spring Boot auto-configures
// a full RedisTemplate, RedisConnectionFactory, and changes your
// cache manager from Caffeine to Redis โ breaking your existing caching!
// โ
Fix: Explicitly exclude unwanted auto-configuration
@SpringBootApplication(exclude = {
RedisAutoConfiguration.class,
RedisRepositoryAutoConfiguration.class
})
public class MyApplication { }
Profile Driftโ
# โ Profile drift: dev and prod have different behavior
# application-dev.yml uses H2 in-memory โ no FK constraints
# application-prod.yml uses PostgreSQL โ strict FK constraints
# Tests pass in dev, fail in production!
# โ
Fix: Use the same database engine in all environments
# application-dev.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/devdb # same engine as prod!
# Or use Testcontainers for integration tests
Fat JAR Size & Startup Timeโ
| Metric | Typical Spring Boot App | Optimized |
|---|---|---|
| JAR size | 50โ100MB | 30โ50MB (exclude unused starters) |
| Startup time | 3โ8 seconds | 1โ3 seconds (lazy init, exclude auto-configs) |
| Memory | 256โ512MB | 128โ256MB (tuned JVM flags) |
| Native image | N/A | 50โ100ms startup, 50โ80MB memory |
When Spring Boot Is NOT the Right Choiceโ
| Scenario | Better Alternative |
|---|---|
| Ultra-low latency (sub-ms) | Quarkus, Micronaut, or hand-tuned Netty |
| Serverless / Lambda | Quarkus (native) or lightweight frameworks |
| Simple CLI tool | Picocli or plain Java |
| Frontend-heavy app | Next.js, Django, Rails |
| Embedded systems | Too heavy for constrained environments |
๐งช Testing in Spring Bootโ
The Testing Pyramidโ
Spring Boot provides specialized test slices that load only what you need:
/ @SpringBootTest \ โ Full integration (slow, few)
/ @WebMvcTest \ โ Controller layer only
/ @DataJpaTest \ โ Repository layer only
/ @MockBean + unit tests \ โ Pure unit tests (fast, many)
// Controller test โ only loads web layer, no database
@WebMvcTest(OrderController.class)
class OrderControllerTest {
@Autowired private MockMvc mockMvc;
@MockBean private OrderService orderService;
@Test
void shouldCreateOrder() throws Exception {
when(orderService.createOrder(any())).thenReturn(testOrder);
mockMvc.perform(post("/api/v1/orders")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"customerId": 1, "items": [{"productId": 42, "quantity": 2}]}
"""))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").exists());
}
}
// Repository test โ only loads JPA, uses embedded database
@DataJpaTest
class OrderRepositoryTest {
@Autowired private OrderRepository repository;
@Test
void shouldFindOrdersByCustomer() {
repository.save(new Order(1L, OrderStatus.PENDING));
List<Order> orders = repository.findByCustomerIdAndStatus(1L, OrderStatus.PENDING);
assertThat(orders).hasSize(1);
}
}
// Full integration test โ loads entire application
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderIntegrationTest {
@Autowired private TestRestTemplate restTemplate;
@Test
void shouldCreateAndRetrieveOrder() {
ResponseEntity<OrderResponse> response = restTemplate.postForEntity(
"/api/v1/orders", createRequest, OrderResponse.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
}
}
| Annotation | What It Loads | Speed | Use For |
|---|---|---|---|
@WebMvcTest | Controllers, filters, converters only | โก Fast | REST API contract testing |
@DataJpaTest | JPA, Hibernate, repositories only | โก Fast | Query and repository testing |
@WebFluxTest | Reactive controllers only | โก Fast | Reactive endpoint testing |
@JsonTest | JSON serialization only | โก Fast | DTO serialization/deserialization |
@SpringBootTest | Everything | ๐ข Slow | End-to-end integration tests |
๐ Relationship to Other Spring Projectsโ
Spring Boot (this page)
โโโ Built on: Spring Framework (IoC, DI, AOP, MVC)
โโโ Data access: Spring Data (JPA, MongoDB, Redis)
โโโ Security: Spring Security (Auth, OAuth2, JWT)
โโโ Messaging: Spring AMQP (RabbitMQ), Spring Kafka
โโโ Cloud: Spring Cloud (Config, Discovery, Gateway, Circuit Breaker)
โโโ Batch: Spring Batch (chunk processing, job scheduling)
โโโ Reactive: Spring WebFlux (non-blocking, Project Reactor)
| Project | What It Adds | Typical Starter |
|---|---|---|
| Spring Data JPA | Repository abstraction for databases | spring-boot-starter-data-jpa |
| Spring Security | Authentication, authorization, CSRF, OAuth2 | spring-boot-starter-security |
| Spring Cloud Config | Centralized configuration management | spring-cloud-starter-config |
| Spring Cloud Netflix | Service discovery (Eureka), client load balancing | spring-cloud-starter-netflix-eureka-* |
| Spring Cloud Gateway | API gateway, routing, rate limiting | spring-cloud-starter-gateway |
| Spring Batch | Large-scale batch processing | spring-boot-starter-batch |
Summaryโ
Spring Boot transforms the Spring development experience by providing:
- Zero-config startup through auto-configuration
- Dependency harmony through starter POMs
- Deployment simplicity through embedded servers and fat JARs
- Operational visibility through Actuator
- Environment flexibility through externalized configuration
It is the foundation for modern Java application development, from monoliths to cloud-native microservices.
Compare Nextโ
Interview Questionsโ
Fundamentalsโ
Q: What is Spring Boot and how does it differ from the Spring Framework?โ
A: Spring Framework provides IoC, DI, AOP, MVC, and other foundational features but requires manual configuration. Spring Boot is a layer on top that provides auto-configuration, starter dependencies, embedded servers, and production-ready features (Actuator). It doesn't replace Spring โ it eliminates boilerplate so you can use Spring faster.
Q: Why is Spring Boot preferred for microservices over plain Spring?โ
A: It reduces setup overhead with auto-configuration and starters, produces self-contained fat JARs perfect for containers, includes Actuator for health/metrics/readiness probes, and supports externalized configuration for environment-specific deployment โ all critical for microservice architecture.
Q: What does @SpringBootApplication do?โ
A: It's a meta-annotation combining @SpringBootConfiguration (marks a configuration class), @EnableAutoConfiguration (enables classpath-based auto-configuration), and @ComponentScan (scans the current package and sub-packages for beans). It's the entry point annotation for every Spring Boot application.
Auto-Configuration & Configurationโ
Q: How does auto-configuration work?โ
A: Spring Boot reads auto-configuration classes from META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (Boot 3.x) or META-INF/spring.factories (Boot 2.x). Each class uses conditional annotations (@ConditionalOnClass, @ConditionalOnMissingBean, etc.) to decide whether to create beans. Your explicit configuration always takes precedence over auto-configuration.
Q: What is the biggest risk of relying heavily on auto-configuration defaults?โ
A: Hidden behavior can change after dependency upgrades โ a new JAR on the classpath can trigger unexpected auto-configuration. Teams should keep critical configuration explicit, use --debug to audit what's auto-configured, and test configuration changes across environments.
Q: How does the externalized configuration priority work?โ
A: Spring Boot resolves properties in order: command-line args > environment variables > application-{profile}.yml > application.yml > defaults. Higher-priority sources override lower ones. This allows the same artifact to run in dev, staging, and production without recompilation.
Q: What is @ConfigurationProperties and when should you use it over @Value?โ
A: @ConfigurationProperties binds a group of related properties to a type-safe POJO, supports validation (@Validated), and works with IDE auto-completion. Use it for structured config (e.g., app.payment.stripe.*). Use @Value only for one-off simple properties.
Production & Operationsโ
Q: What operational checks should every Spring Boot service expose?โ
A: Health (overall app status), readiness (can it accept traffic?), liveness (is it hung?), key latency/error metrics, and dependency status (database, cache, downstream services). All achievable through Spring Boot Actuator.
Q: How do profiles impact deployment safety?โ
A: They separate environment behavior without rebuilding artifacts, but can cause "profile drift" where dev uses H2 and prod uses PostgreSQL, leading to bugs that only appear in production. Mitigate by using the same database engine across all environments and testing with Testcontainers.
Q: How do you optimize Spring Boot startup time?โ
A: Lazy initialization (spring.main.lazy-initialization=true), exclude unused auto-configurations, use Spring AOT with GraalVM Native Image for sub-100ms startup, and Class Data Sharing (CDS). Trade-offs: lazy init makes the first request slower; native images have longer build times and reflection limitations.
Architecture & Designโ
Q: When should you avoid adding another starter dependency?โ
A: When it introduces broad transitive features you don't need (e.g., adding starter-data-redis just for the client triggers auto-configuration of RedisTemplate, cache manager, etc.). Explicitly exclude unwanted auto-configs or depend on the raw library instead.
Q: How do you handle feature rollout safely in Spring Boot services?โ
A: Use feature flags (e.g., LaunchDarkly, Unleash, or Spring Cloud Config) so deployment and release are decoupled. Deploy the code with the feature disabled, then gradually enable it for a percentage of users. This separates "shipping code" from "activating behavior."
Q: When would you choose Quarkus or Micronaut over Spring Boot?โ
A: For serverless/FaaS where cold-start time is critical (Quarkus native compiles in ~50ms vs Boot's ~3s). For extremely memory-constrained environments (IoT, edge computing). Spring Boot's advantage is ecosystem breadth, community size, and enterprise tooling โ Quarkus/Micronaut are better for specific performance-critical scenarios.
Q: How does Spring Boot support 12-Factor App methodology?โ
A: Externalized config (env vars, profiles) โ Factor III. Fat JAR deployment โ Factor V (build, release, run). Stateless services โ Factor VI. Port binding (embedded server) โ Factor VII. Actuator health checks โ Factor VIII (telemetry). Graceful shutdown โ Factor IX (disposability).