Introduction to Spring Boot
Spring Boot is an opinionated framework built on top of the Spring Framework that makes it radically easier to create stand-alone, production-grade Spring applications. Its motto: "just run" — minimal configuration, an embedded server, and sensible defaults.
What It Gives You
- Auto-configuration — wires beans based on the classpath, so you write almost no XML/config.
- Starters — curated dependency bundles (
spring-boot-starter-web). - Embedded server — Tomcat/Jetty/Undertow built in; run a fat JAR with
java -jar. - Actuator — production endpoints (health, metrics) out of the box.
- No code generation, no XML — convention over configuration.
@SpringBootApplication bundles three annotations: @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan. That one line is the whole "magic."Spring Framework vs Spring Boot
Spring Framework is the core (IoC, DI, MVC, data). Spring Boot is a layer on top that removes the boilerplate of configuring it.
| Spring Framework | Spring Boot | |
|---|---|---|
| Configuration | Manual (XML/Java config) | Auto-configured |
| Server | External (deploy WAR) | Embedded (fat JAR) |
| Dependencies | Pick each manually | Starters bundle them |
| Setup time | High | Minutes |
| Production features | Add yourself | Actuator built-in |
Spring Boot Architecture
A typical Spring Boot app is layered, with requests flowing through clearly-separated tiers.
- Controller layer — HTTP endpoints, request/response mapping.
- Service layer — business logic, transactions.
- Repository layer — data access (Spring Data JPA).
- Model/Entity — domain objects.
Spring Boot Starters
Starters are curated dependency descriptors — add one and you get a whole consistent set of compatible libraries, version-managed for you.
| Starter | Brings in |
|---|---|
spring-boot-starter-web | Spring MVC, Jackson, embedded Tomcat |
spring-boot-starter-data-jpa | Hibernate, Spring Data, JDBC |
spring-boot-starter-security | Spring Security |
spring-boot-starter-actuator | Production endpoints |
spring-boot-starter-test | JUnit 5, Mockito, AssertJ |
spring-boot-starter-parent (or BOM), so you never specify versions for starter-managed libs — eliminating dependency conflicts.Spring Boot Auto Configuration
Auto-configuration is Spring Boot's defining feature: it automatically configures beans based on what's on the classpath, what beans already exist, and your properties — so you get a working app with almost zero manual config.
How It Works — Visual
The Mechanism
@EnableAutoConfiguration(inside@SpringBootApplication) triggers it.- Spring reads auto-config classes listed in
META-INF/spring/...AutoConfiguration.imports. - Each is gated by @Conditional annotations:
| Condition | Applies config if… |
|---|---|
@ConditionalOnClass | A class is on the classpath (e.g. DataSource) |
@ConditionalOnMissingBean | You haven't defined that bean yourself |
@ConditionalOnProperty | A property is set |
@ConditionalOnMissingBean means your beans always win — auto-config only fills gaps. Add the JPA starter → a DataSource auto-configures; define your own DataSource → Boot backs off. Disable specific ones with @SpringBootApplication(exclude=...).Spring Boot Project Structure
A conventional package-by-layer (or package-by-feature) structure keeps Spring Boot apps maintainable.
Application.java in the root package — component scanning starts there and covers all sub-packages automatically. Misplacing it (too deep) is a common "my beans aren't found" bug.Spring Boot Annotations
A quick reference to the annotations you'll use constantly.
| Annotation | Purpose |
|---|---|
@SpringBootApplication | Main entry (config + auto-config + scan) |
@RestController / @Controller | Web endpoints |
@Service / @Repository / @Component | Beans by role |
@Autowired | Inject a dependency |
@Configuration / @Bean | Java-based bean definitions |
@Value / @ConfigurationProperties | Bind properties |
@GetMapping / @PostMapping … | Route HTTP methods |
@Transactional | Declarative transactions |
@RestController = @Controller + @ResponseBody). Understanding the composition demystifies them.Dependency Injection (DI) & IoC
Inversion of Control (IoC) means the framework — not your code — creates and wires objects. Dependency Injection is how IoC is implemented: Spring injects a class's dependencies instead of the class constructing them itself. The result: loose coupling and easy testing.
Without vs With DI — Visual
Constructor Injection (Recommended)
Three Injection Types
| Type | Notes |
|---|---|
| Constructor (best) | Immutable, testable, fails fast, allows final |
| Setter | For optional dependencies |
Field (@Autowired) | Concise but hard to test, no final — avoid |
new + mocks. Since Spring 4.3, a single constructor needs no @Autowired.Inversion of Control (IoC)
IoC is the principle that control over object creation and lifecycle is inverted — handed from your code to a container. The Spring IoC Container (ApplicationContext) creates, configures, wires, and manages beans.
- BeanFactory — basic container.
- ApplicationContext — full-featured (events, i18n, AOP); what you actually use.
Spring Beans
A bean is simply an object that the Spring IoC container creates, manages, and wires. You declare beans by annotating classes (@Component & friends) or with @Bean methods in a @Configuration class.
@Bean methods (for third-party classes you can't annotate).Bean Lifecycle
The container manages a bean from creation to destruction through well-defined phases — with hooks you can tap into for initialization and cleanup.
Lifecycle Phases — Visual
Hooks (in order)
- Constructor → dependency injection →
@PostConstruct→InitializingBean.afterPropertiesSet()→ custominitMethod. - On shutdown:
@PreDestroy→DisposableBean.destroy()→ customdestroyMethod. BeanPostProcessorcan intercept all beans before/after init (how AOP proxies are applied).
@PostConstruct for setup needing injected dependencies (the constructor runs before injection). Prototype-scoped beans get no destruction callback — the container doesn't manage their full lifecycle.Bean Scopes
A bean's scope defines its lifecycle and how many instances exist. The default — singleton — means one shared instance per container.
| Scope | Instances | Use |
|---|---|---|
singleton (default) | One per container | Stateless services |
prototype | New on each injection/lookup | Stateful, short-lived |
request | One per HTTP request | Web |
session | One per HTTP session | Web |
application | One per ServletContext | Web |
ObjectProvider or scoped proxies to get fresh ones.Component Scanning
Component scanning is how Spring discovers your beans — it scans packages for classes annotated with @Component (and its specializations) and registers them automatically.
@SpringBootApplication class and includes all sub-packages — which is why the main class belongs in the root package. Beans outside that tree won't be found unless you add @ComponentScan.@Component
@Component is the generic stereotype marking a class as a Spring-managed bean, eligible for component scanning. @Service, @Repository, and @Controller are specializations of it.
@Component for general helpers that don't fit the service/repository/controller roles. The specialized stereotypes add semantics (and behaviour, like exception translation for @Repository).@Service
@Service marks a class holding business logic — the service layer. Functionally identical to @Component, but it documents intent and is the conventional place for @Transactional logic.
@Repository
@Repository marks the data-access layer. Beyond being a bean, it enables exception translation — converting vendor-specific persistence exceptions into Spring's consistent DataAccessException hierarchy.
@Repository annotation is optional there but still good for clarity in custom DAO classes.@Controller
@Controller marks a web controller in Spring MVC. By default its methods return view names (rendered by a template engine like Thymeleaf), not response bodies.
@Controller for server-rendered HTML (this very site uses it with Thymeleaf). For JSON REST APIs, use @RestController (next).@RestController
@RestController = @Controller + @ResponseBody. Every method returns data (serialized to JSON by Jackson) directly as the HTTP response body — the standard for REST APIs.
@Controller returns view names; @RestController returns serialized objects (JSON/XML). No need to annotate each method with @ResponseBody.application.properties
The default config file (in src/main/resources). Key-value pairs configure the app, server, datasource, logging, and any custom property.
${...} and inject with @Value or @ConfigurationProperties.application.yml
YAML is an alternative to .properties — hierarchical, less repetitive, and easier to read for nested config.
.properties and .yml for the same keys — pick one. YAML also supports multi-document files (---) for per-profile config.Profiles (@Profile)
Profiles let you define environment-specific configuration and beans (dev, staging, prod) and switch between them at runtime.
Configuration Properties
@ConfigurationProperties binds a group of related properties to a strongly-typed POJO — cleaner and safer than scattering @Value everywhere.
| @Value | @ConfigurationProperties | |
|---|---|---|
| Binds | One property | A group (prefix) |
| Type-safe | Limited | Yes (+ validation) |
| Relaxed binding | No | Yes (kebab/camel/env) |
@ConfigurationProperties for grouped config — it supports validation (@Validated), relaxed binding (app.mail.from = APP_MAIL_FROM), and IDE metadata.Externalized Configuration
Spring Boot lets you externalize config so the same code runs in any environment — pulling values from many sources in a defined precedence order.
Precedence (high → low)
- Command-line args (
--server.port=9000) - OS environment variables (
SERVER_PORT) - External
application.yml(outside the jar) - Profile-specific files
- Packaged
application.yml
REST API Development & Design
REST (Representational State Transfer) is an architectural style for web APIs: resources identified by URLs, manipulated with HTTP verbs, communicating statelessly. Spring Boot makes building them trivial.
Resource + Verb Mapping — Visual
A Complete Controller
REST Design Best Practices
- Nouns, not verbs in URLs (
/users, not/getUsers); plural resources. - Correct status codes (200, 201, 204, 400, 404, 409, 500).
- Stateless — no server session; auth via token per request.
- Use DTOs (not entities) at the boundary; validate input; version the API.
- Consistent error responses, pagination for collections, HATEOAS optional.
Request Mapping
@RequestMapping (and its shortcuts) map HTTP requests to handler methods by path, method, headers, and content type.
@GetMapping etc.) over generic @RequestMapping — clearer and less error-prone. Class-level @RequestMapping sets a base path for all methods.Path Variables
@PathVariable binds a URI template segment to a method parameter — for identifying a specific resource.
/users/42). For optional filters/search, use query parameters instead (next topic).Request Parameters
@RequestParam binds query-string (or form) parameters — for filtering, sorting, and pagination.
defaultValue / required=false for optional params. Path variable = identity; request param = options/filters.Request Body
@RequestBody deserializes the HTTP request body (JSON) into a Java object via Jackson — used for POST/PUT payloads.
@RequestBody with @Valid to validate the payload before your method runs. Accept a DTO, not your entity, to control the API contract.Response Entity
ResponseEntity<T> gives full control over the HTTP response — status code, headers, and body — instead of just returning the body.
ResponseEntity when you need custom status, headers, or conditional responses (404 vs 200).API Versioning
Versioning lets you evolve an API without breaking existing clients. Several strategies:
| Strategy | Example |
|---|---|
| URI path | /api/v1/users (most common, clear) |
| Query param | /api/users?version=1 |
| Header | X-API-Version: 1 |
| Content negotiation | Accept: application/vnd.app.v1+json |
/v1/) is the most popular for its simplicity and cache-friendliness. Whatever you pick, keep old versions running during a deprecation window and communicate the timeline.Exception Handling
Robust APIs translate exceptions into meaningful, consistent HTTP responses. Spring offers per-controller (@ExceptionHandler) and global (@RestControllerAdvice) handling.
Flow — Visual
@RestControllerAdvice for one centralized place that converts every exception into a consistent error shape. Map domain exceptions to proper status codes (404, 409, 400) — never leak stack traces to clients.Global Exception Handling
@RestControllerAdvice (= @ControllerAdvice + @ResponseBody) applies @ExceptionHandler methods across all controllers — DRY, consistent error handling.
ResponseEntityExceptionHandler to customize Spring's built-in exceptions (validation, 404, etc.). Consider RFC 7807 ProblemDetail (Spring 6) for standardized error bodies.Validation (@Valid)
Bean Validation (Jakarta Validation / Hibernate Validator) declaratively validates request data using annotations. @Valid triggers it; failures become 400 Bad Request.
Constraint Annotations
| Annotation | Checks |
|---|---|
@NotNull / @NotBlank / @NotEmpty | Presence |
@Size / @Min / @Max | Bounds |
@Email / @Pattern | Format |
@Past / @Future | Dates |
@Valid on a @RequestBody throws MethodArgumentNotValidException on failure — catch it in your @RestControllerAdvice to return field-level error messages. Use @Validated at class level for method-parameter validation and validation groups.Custom Validation
When built-in constraints aren't enough, create a custom annotation backed by a ConstraintValidator.
Spring Data JPA
Spring Data JPA eliminates boilerplate data-access code: you declare a repository interface and Spring generates the implementation at runtime — including queries derived from method names.
The Layers — Visual
Derived Query Methods
Spring parses the method name (findBy + properties + keywords like GreaterThan, Between, OrderBy) and writes the query for you.
JpaRepository, plus name-derived queries, and @Query for anything complex. Interview gold: "I extend JpaRepository and let Spring generate queries from method names; complex ones use @Query (JPQL or native)."Hibernate
Hibernate is the default JPA implementation (ORM) in Spring Boot — it maps Java objects to database tables and generates SQL, so you work with objects, not rows.
- JPA is the specification (interfaces/annotations); Hibernate is the implementation.
- Manages the persistence context (first-level cache) and entity state (transient/managed/detached).
- Dirty checking — auto-updates changed managed entities at flush time.
spring.jpa.hibernate.ddl-auto controls schema generation (use validate/none in prod, never create).Entity Mapping
An @Entity class maps to a database table; its fields map to columns via annotations.
@Id. Store enums as STRING (not ORDINAL — reordering breaks data). Use wrapper types (Long) for ids so null = "not yet persisted."Relationships (OneToOne, OneToMany, ManyToMany)
JPA maps table relationships to object references.
| Type | Owning side / default fetch |
|---|---|
| @OneToOne | FK side / EAGER |
| @ManyToOne | FK side / EAGER |
| @OneToMany | mappedBy (inverse) / LAZY |
| @ManyToMany | Join table / LAZY |
@ManyToOne/@OneToOne LAZY explicitly (default EAGER causes surprise queries). Use mappedBy on the inverse side to avoid duplicate FK columns. Watch for the N+1 query problem (see Lazy Loading).CRUD Repository
CrudRepository<T, ID> provides the basic create-read-update-delete operations for an entity.
CrudRepository is the base; JpaRepository extends it with paging, sorting, batch ops, and flush. Most apps extend JpaRepository directly.JpaRepository
JpaRepository<T, ID> is the richest standard repository — extends PagingAndSortingRepository + CrudRepository and adds JPA-specific methods.
Repository → CrudRepository → PagingAndSortingRepository → JpaRepository. Default to JpaRepository unless you want to deliberately restrict the API.Paging and Sorting
For large datasets, return data in pages with Pageable / Page instead of loading everything.
Pageable directly from request params (?page=0&size=20&sort=name,desc). Use Slice when you only need "is there a next page" (avoids the count query).Custom Queries
When derived method names get unwieldy, write the query explicitly with @Query.
@Query defaults to JPQL; add nativeQuery=true for raw SQL. Use @Modifying for UPDATE/DELETE. See JPQL and Native Queries for details.JPQL
JPQL (Java Persistence Query Language) is an object-oriented query language — it queries entities and their fields, not tables and columns. Portable across databases.
User, u.name), not table/column names. JOIN FETCH eagerly loads associations in one query — the standard fix for the N+1 problem.Native Queries
Native queries run raw SQL — for database-specific features, complex queries, or performance tuning that JPQL can't express.
:param) — never concatenate input (SQL injection).Transaction Management
A transaction groups operations into an all-or-nothing (ACID) unit. Spring's @Transactional makes this declarative — begin, commit, and rollback are handled around your method via an AOP proxy.
How the Proxy Works — Visual
Key Rules & Gotchas
- By default rolls back on unchecked exceptions (RuntimeException/Error), not checked — override with
rollbackFor. - Works via a proxy → self-invocation doesn't work (calling a
@Transactionalmethod from within the same class bypasses the proxy). - Put
@Transactionalon the service layer, not controllers/repositories. - Use
readOnly = truefor queries (optimization hint).
@Transactional
The annotation that declares a transactional boundary. Key attributes:
| Attribute | Purpose |
|---|---|
propagation | How it joins/creates transactions |
isolation | Concurrency visibility level |
readOnly | Optimization for read queries |
rollbackFor / noRollbackFor | Which exceptions trigger rollback |
timeout | Max duration before rollback |
Propagation Types
Propagation defines how a transactional method behaves when called within an existing transaction.
| Propagation | Behaviour |
|---|---|
REQUIRED (default) | Join existing, or create a new one |
REQUIRES_NEW | Always start a new tx (suspend the outer) |
SUPPORTS | Join if one exists, else run non-tx |
MANDATORY | Must run in an existing tx, else error |
NESTED | Nested tx with savepoint |
NOT_SUPPORTED / NEVER | Run non-tx / fail if tx exists |
REQUIRES_NEW for an audit log that must commit even if the main transaction rolls back. Default REQUIRED is right for most service methods.Isolation Levels
Isolation controls how/when one transaction's changes are visible to others — trading consistency against concurrency.
| Level | Prevents |
|---|---|
| READ_UNCOMMITTED | Nothing (dirty reads possible) |
| READ_COMMITTED | Dirty reads |
| REPEATABLE_READ | Dirty + non-repeatable reads |
| SERIALIZABLE | All anomalies (incl. phantom reads) |
Anomalies: dirty read (read uncommitted data), non-repeatable read (row changes between reads), phantom read (new rows appear).
READ_COMMITTED is the common default (Postgres/Oracle). Raise it only when you hit a specific anomaly.Lazy Loading
Lazy loading defers fetching an association until it's actually accessed — saving queries when you don't need the related data.
LazyInitializationException — accessing a lazy field after the session closes (outside the transaction); fix with JOIN FETCH or a DTO projection. (2) The N+1 problem — looping over N parents each lazily loading children = N+1 queries; fix with JOIN FETCH or @EntityGraph.Eager Loading
Eager loading fetches an association immediately with its parent. Default for @ManyToOne/@OneToOne.
| Lazy | Eager | |
|---|---|---|
| When loaded | On access | With parent |
| Default for | @OneToMany, @ManyToMany | @ManyToOne, @OneToOne |
| Risk | LazyInit / N+1 | Loads unneeded data, big joins |
JOIN FETCH / @EntityGraph). Default EAGER on @ManyToOne is a common source of accidental over-fetching.Spring Security
Spring Security is the framework for authentication (who are you?) and authorization (what can you do?). It works as a chain of servlet filters intercepting every request before it reaches your controller.
The Filter Chain — Visual
Core Concepts
- AuthenticationManager → UserDetailsService → PasswordEncoder verify credentials.
- SecurityContextHolder holds the authenticated principal (per thread).
- GrantedAuthority/roles drive authorization.
SecurityFilterChain bean (no more WebSecurityConfigurerAdapter). For REST APIs: stateless sessions + JWT + CSRF disabled.Authentication
Authentication verifies who the user is — validating credentials (password, token, certificate) and establishing identity.
| Method | Use |
|---|---|
| Form login / Basic | Traditional web / simple APIs |
| JWT (bearer token) | Stateless REST APIs |
| OAuth2 / OIDC | Delegated / SSO |
UserDetailsService to load users from your database, paired with a BCryptPasswordEncoder to verify hashed passwords.Authorization
Authorization decides what an authenticated user may do — enforced at URL level or method level via roles/authorities.
hasRole('ADMIN') checks authority ROLE_ADMIN (the prefix is added automatically). Method security with SpEL (@PreAuthorize) enables fine-grained, expression-based rules including ownership checks.OAuth 2.0
OAuth 2.0 is a delegated authorization framework — it lets an app access resources on a user's behalf without handling their password. OIDC adds an identity layer on top.
| Role | Who |
|---|---|
| Resource Owner | The user |
| Client | Your app |
| Authorization Server | Issues tokens (Keycloak, Auth0, Google) |
| Resource Server | The API serving protected data |
JWT Authentication
JWT (JSON Web Token) enables stateless authentication: the server issues a signed token the client sends on every request, so no server-side session is needed — ideal for REST APIs and microservices.
Login → Token → Access — Visual
Token Structure
Three base64 parts: header.payload.signature — header (algorithm), payload (claims: sub, roles, exp), signature (verifies integrity with a secret/key).
Role-Based Access Control (RBAC)
RBAC grants permissions based on roles assigned to users, rather than to individuals — the standard authorization model.
hasRole("X") (expects ROLE_X) from hasAuthority("perm:read") (exact match). For fine-grained control, grant authorities, not just roles.Password Encoding
Never store passwords in plain text. Spring Security hashes them with a one-way, salted, slow algorithm via PasswordEncoder.
DelegatingPasswordEncoder (the default) supports upgrading algorithms over time.Session Management
For session-based auth, Spring tracks logged-in users via a session cookie (JSESSIONID). You can control concurrency, fixation protection, and timeouts.
Stateless Applications
A stateless app keeps no server-side session — each request carries everything needed to authenticate (a JWT). Any instance can serve any request, enabling effortless horizontal scaling.
| Stateful (session) | Stateless (JWT) | |
|---|---|---|
| Server stores | Session | Nothing |
| Scaling | Sticky / shared store | Any instance |
| Auth carried by | Cookie | Bearer token |
REST API Security
Securing a REST API combines authentication, authorization, transport security, and input hardening.
- HTTPS everywhere — encrypt in transit (TLS).
- Stateless auth — JWT/OAuth2 bearer tokens; CSRF can be disabled for token-based APIs.
- Authorization — least-privilege roles, method-level checks.
- Input validation —
@Valid, parameterized queries (no SQL injection). - Rate limiting & CORS — throttle abuse; restrict origins.
- Security headers — HSTS, content-type, frame options.
OpenAPI Specification
OpenAPI (formerly Swagger Spec) is a standard, language-agnostic format for describing REST APIs — endpoints, parameters, schemas, responses — in JSON/YAML. Tools generate docs, clients, and tests from it.
Swagger / OpenAPI Integration
Swagger UI gives you auto-generated, interactive API documentation. With springdoc-openapi, you add one dependency and get a live docs page that reads your controllers.
/v3/api-docs, rendered interactively at /swagger-ui.html. Add @Operation/@Schema for richer docs; secure or disable these endpoints in production.Spring Boot Actuator
Actuator exposes production-ready endpoints for monitoring and managing a running app — health, metrics, info, env, loggers — over HTTP or JMX. Essential for observability and Kubernetes probes.
Key Endpoints
| Endpoint | Shows |
|---|---|
/actuator/health | App + dependency health (DB, disk, Redis) |
/actuator/metrics | JVM, HTTP, custom metrics |
/actuator/prometheus | Metrics in Prometheus format |
/actuator/info | Build/version info |
/actuator/loggers | View/change log levels at runtime |
/actuator/env | Configuration properties |
health/info are exposed by default. Lock the rest behind authentication and never expose them publicly. The liveness/readiness sub-endpoints map directly to K8s probes.Health Checks
/actuator/health aggregates the status of the app and its dependencies. Load balancers and orchestrators use it to route traffic only to healthy instances.
HealthIndicator beans are auto-aggregated into the overall status.Metrics Monitoring
Actuator uses Micrometer — a vendor-neutral metrics facade — to collect JVM, HTTP, and custom metrics and export them to Prometheus, Datadog, CloudWatch, etc.
Logging
Spring Boot uses SLF4J (facade) + Logback (default implementation) out of the box. Configure levels via properties; log to stdout for cloud-native apps.
{}) — it skips string building when the level is disabled. In containers, log to stdout (12-factor) and let the platform aggregate. Add org.projectlombok:lombok + @Slf4j to skip the boilerplate logger line.SLF4J
SLF4J (Simple Logging Facade for Java) is an abstraction over logging frameworks. You code against SLF4J; the actual implementation (Logback, Log4j2) is swappable without changing code.
Logback
Logback is Spring Boot's default logging implementation. Customize it via logback-spring.xml — appenders (where logs go), encoders (format), and rolling policies.
logback-spring.xml (not logback.xml) so Spring profile/property substitution works. For centralized logging (ELK/Loki), emit structured JSON and include a trace/correlation id (MDC).Distributed Tracing & Observability
In microservices, one user request spans many services. Distributed tracing stitches those hops into a single end-to-end trace so you can see where latency and errors occur. Observability rests on three pillars: metrics, logs, traces.
A Trace Across Services — Visual
OpenTelemetry
OpenTelemetry (OTel) is the vendor-neutral CNCF standard for generating and exporting traces, metrics, and logs — one set of APIs/SDKs, any backend.
- Instrument once with OTel; export to Jaeger, Tempo, Prometheus, Datadog, etc.
- Spring Boot 3 integrates via Micrometer Tracing (bridge to OTel).
- The OTel Collector receives, processes, and routes telemetry.
Caching
Caching stores expensive results so repeated requests are served fast, reducing DB load and latency. Spring's cache abstraction makes it declarative — annotate a method and Spring handles the cache lookup/store.
Cache-Aside Flow — Visual
| Annotation | Effect |
|---|---|
@Cacheable | Return cached value or compute & store |
@CachePut | Always run & update the cache |
@CacheEvict | Remove entry/entries |
Redis Integration
Redis is an in-memory data store used as a distributed cache, session store, rate-limiter, and pub/sub broker. Spring Data Redis + the cache starter make it the standard distributed cache backend.
spring.cache.type=redis, your @Cacheable methods transparently use Redis — so the cache is shared across all app instances (unlike a local in-JVM cache). Also great for shared sessions (Spring Session) and rate limiting.Spring Boot Testing
spring-boot-starter-test bundles JUnit 5, Mockito, AssertJ, and Spring Test. Spring Boot supports the full test pyramid: many fast unit tests, fewer integration tests, even fewer end-to-end.
| Annotation | Loads |
|---|---|
@SpringBootTest | Full application context (integration) |
@WebMvcTest | Web layer only (controllers) |
@DataJpaTest | JPA layer only (repositories + H2) |
@MockBean | Replace a bean with a mock |
@WebMvcTest, @DataJpaTest) for speed — they load only the relevant layer. Reserve @SpringBootTest for true integration tests; it boots the whole context and is slower.Unit Testing
Unit tests verify a single class in isolation, mocking its dependencies — no Spring context, so they're fast.
new OrderService(mockRepo) — no container needed. Follow Arrange-Act-Assert.Integration Testing
Integration tests verify multiple components working together (controller → service → repository → DB) with a real or near-real Spring context.
MockMvc tests the web layer without a real server; TestRestTemplate/WebTestClient hit a running random-port server. Use Testcontainers for a real database instead of H2 (next).JUnit 5
JUnit 5 (Jupiter) is the standard testing framework — annotations, assertions, parameterized tests, and lifecycle hooks.
@Test, @BeforeEach/@AfterEach, @BeforeAll, @ParameterizedTest, @Nested. Pair with AssertJ (assertThat(x).isEqualTo(y)) for fluent, readable assertions.Mockito
Mockito creates mock objects so you can test a class in isolation — stubbing dependency behaviour and verifying interactions.
@Mock creates a mock; @InjectMocks injects mocks into the class under test. In Spring integration tests use @MockBean to replace a bean in the context with a mock.TestContainers
Testcontainers spins up real dependencies (PostgreSQL, Kafka, Redis) in Docker containers for tests — so you test against the real thing, not an in-memory substitute like H2.
@ServiceConnection auto-configures the datasource from the container — no manual property wiring.Spring Boot DevTools
DevTools speeds up development with automatic restart on code changes, live reload for the browser, and dev-friendly defaults (disabled caching).
Spring Boot with Docker & Kubernetes
Spring Boot's fat JAR + embedded server makes it ideal for containers. Package it as a Docker image, then run it on Kubernetes for scaling and self-healing.
Dockerizing (Multi-Stage)
Or skip the Dockerfile entirely with Buildpacks: ./mvnw spring-boot:build-image.
Kubernetes Deployment
/health/liveness & /readiness to K8s probes, set -XX:MaxRAMPercentage for the container memory limit, and enable graceful shutdown (server.shutdown=graceful).Spring Boot with Kubernetes
Beyond a basic Deployment, Spring Boot has first-class Kubernetes support.
- Health probes — Actuator's liveness/readiness groups map to K8s probes.
- Config — mount ConfigMaps/Secrets as env vars or files;
spring-cloud-kubernetescan read them directly. - Graceful shutdown —
server.shutdown=gracefuldrains in-flight requests on SIGTERM. - Service discovery — use native K8s Services/DNS (often instead of Eureka).
Spring Boot with AWS
Spring Boot runs well across AWS compute options and integrates with AWS services via Spring Cloud AWS.
| Run on | Notes |
|---|---|
| EC2 | Run the jar / systemd; full control |
| ECS / Fargate | Containers, serverless option |
| EKS | Managed Kubernetes |
| Elastic Beanstalk | PaaS, quick deploys |
| Lambda | Spring Cloud Function + SnapStart |
Microservices Architecture
Microservices split an application into small, independently deployable services, each owning a business capability and its data. Spring Cloud provides the supporting patterns.
Typical Topology — Visual
Core Patterns (Spring Cloud)
| Pattern | Spring tool |
|---|---|
| API Gateway | Spring Cloud Gateway |
| Service Discovery | Eureka / Consul / K8s DNS |
| Centralized Config | Spring Cloud Config |
| Resilience | Resilience4j (circuit breaker) |
| Async messaging | Kafka / RabbitMQ |
| Tracing | Micrometer Tracing + OTel |
Service Discovery & API Gateway
In a dynamic system instances come and go with changing IPs. Service discovery lets services find each other by logical name; an API Gateway gives clients one entry point that routes to them.
Discovery Flow — Visual
- Services register with the registry on startup and send heartbeats.
- Callers look up a service by name and get healthy instances (client-side load balancing via Spring Cloud LoadBalancer).
- The gateway routes external requests to services (often using the registry), handling auth, rate limiting, and cross-cutting concerns.
Eureka Server
Netflix Eureka is a service registry. Services register with it and discover each other through it — the classic Spring Cloud discovery solution.
http://order-service/...) with client-side load balancing — no hardcoded hosts. Run multiple Eureka nodes for HA.API Gateway
An API Gateway is the single entry point for all client requests — routing them to backend services and handling cross-cutting concerns (auth, rate limiting, CORS, logging) in one place.
What It Centralizes
Routing
Path/host → service mapping, with load balancing via the registry.
Security
Authenticate/authorize once at the edge; pass identity downstream.
Rate limiting
Throttle abusive clients before they reach services.
Resilience & observability
Timeouts, retries, circuit breakers, request logging/tracing.
Spring Cloud Gateway
Spring Cloud Gateway is the official, reactive (WebFlux/Netty) API gateway. It's built on routes = predicates (match) + filters (transform).
Config Server
Spring Cloud Config Server centralizes configuration for all microservices in one place (usually a Git repo) — so config is versioned, auditable, and changeable without redeploying.
@RefreshScope + Actuator /refresh (or Spring Cloud Bus) to update config at runtime without restarts. On Kubernetes, ConfigMaps/Secrets often serve this role instead.Circuit Breaker (Resilience4j)
A circuit breaker prevents cascading failures: when a downstream service keeps failing, the breaker "opens" and fails fast (or returns a fallback) instead of hammering the broken service and exhausting threads.
The Three States — Visual
Resilience4j
Resilience4j is the lightweight, functional fault-tolerance library for Spring Boot (replacing the deprecated Hystrix). It provides composable resilience patterns.
| Pattern | Purpose |
|---|---|
| CircuitBreaker | Stop calling a failing service |
| Retry | Retry transient failures |
| RateLimiter | Cap call rate |
| Bulkhead | Isolate resource pools |
| TimeLimiter | Timeout slow calls |
Kafka Integration
Apache Kafka is a distributed event-streaming platform. Spring for Apache Kafka makes producing and consuming events simple — the backbone of event-driven microservices.
Producer → Topic → Consumers — Visual
Key Concepts
- Topic split into partitions for parallelism; ordering is guaranteed per partition.
- Consumer groups — each group gets all messages; within a group, partitions are split across consumers.
- Offsets track progress; messages are retained (replayable), unlike a queue.
RabbitMQ Integration
RabbitMQ is a traditional message broker (AMQP) for decoupling services with queues. Spring AMQP makes producing/consuming straightforward.
Core concepts: Exchange (routes by rules) → bindings → Queue → consumer. Exchange types: direct, topic, fanout, headers.
Event-Driven Architecture
In EDA, services communicate by emitting and reacting to events rather than calling each other directly — yielding loose coupling, scalability, and resilience.
- Loose coupling — publishers don't know consumers.
- Patterns — event notification, event-carried state transfer, event sourcing, CQRS.
ApplicationEventPublisher for in-process decoupling; use a broker (Kafka/RabbitMQ) for cross-service events. The trade-off: eventual consistency and harder debugging (mitigate with tracing).Async Processing
@Async runs a method on a separate thread so the caller doesn't block — for fire-and-forget work like emails, notifications, or report generation.
@Async works via a proxy — like @Transactional, self-invocation doesn't work, and the method should return void or CompletableFuture. Always define a custom Executor (the default is unbounded) and handle exceptions (they won't propagate to the caller).CompletableFuture
CompletableFuture enables non-blocking, composable async pipelines — combine several async calls without blocking threads.
@Async methods returning CompletableFuture to parallelize independent calls (e.g. fan-out to several services) and cut total latency. Chain with thenApply/thenCompose/exceptionally.Scheduling
@Scheduled runs tasks on a timer — cron, fixed rate, or fixed delay — for cleanups, reports, and polling.
Batch Processing
Spring Batch processes large volumes of data in chunks with restartability, retry/skip, and transaction management — for ETL, migrations, and report generation.
File Upload & Download
Handle multipart uploads with MultipartFile and stream downloads with Resource/ResponseEntity.
WebClient vs RestTemplate
Both make HTTP calls to other services. RestTemplate is the classic synchronous (blocking) client — now in maintenance mode. WebClient is the modern, non-blocking, reactive client (works for both sync and async).
Comparison
| RestTemplate | WebClient | |
|---|---|---|
| Model | Synchronous, blocking | Async, non-blocking (reactive) |
| Threads | One per call (blocks) | Few event-loop threads |
| Status | Maintenance mode | Recommended |
| Streaming | Limited | Yes (Flux) |
.block(). For new code, use WebClient." It shines for parallel/streaming calls without thread-per-request cost.RestTemplate
The classic synchronous HTTP client for calling REST APIs. Simple and familiar, but blocking and now in maintenance mode.
Reactive Programming (WebFlux)
Spring WebFlux is the reactive, non-blocking web stack (alternative to Spring MVC). Built on Project Reactor (Mono/Flux), it handles high concurrency with few threads.
| Spring MVC | WebFlux | |
|---|---|---|
| Model | Blocking, thread-per-request | Non-blocking, event loop |
| Best for | Most apps, simpler | High concurrency, streaming |
| Server | Tomcat | Netty |
Spring Boot Best Practices
✓ Do
- Constructor injection (not field)
- Keep controllers thin, logic in services
- Use DTOs at the API boundary (not entities)
@Transactionalon the service layer- Validate input with
@Valid - Global exception handling (
@RestControllerAdvice) - Externalize config; profiles per env
- Lazy associations + fetch explicitly
- Actuator + metrics + structured logging
✗ Avoid
- Field injection &
@Autowiredeverywhere - Business logic in controllers
- Exposing entities directly
- EAGER fetching / N+1 queries
ddl-auto=updatein production- Secrets in code / properties in Git
- Catching & swallowing exceptions
- Stateful singletons
Spring Boot Performance Tuning
Performance tuning spans the database, caching, threads/connections, and the JVM. Always profile first to find the real bottleneck.
Database (biggest wins)
Fix N+1 (JOIN FETCH / @EntityGraph), add indexes, paginate, tune the HikariCP pool, use projections/DTOs.
Caching
@Cacheable hot reads (Redis/Caffeine) with TTL to offload the DB.
Connection pools
Right-size HikariCP & HTTP client pools; avoid exhaustion under load.
Async & parallel
Offload non-critical work (@Async); parallelize independent calls (CompletableFuture).
JVM/GC
Right heap (-Xmx/MaxRAMPercentage), G1/ZGC, reduce allocation.
Startup
Lazy init, AOT/native image (GraalVM), CDS for faster boot.
Security Best Practices
- HTTPS/TLS everywhere; HSTS & security headers.
- Hash passwords with BCrypt/Argon2; never store plaintext.
- Stateless auth (JWT/OAuth2) with short-lived tokens.
- Validate & sanitize all input; parameterized queries (no SQLi).
- Least privilege RBAC; check object-level ownership.
- Secrets in a vault/secret manager, never in Git.
- Dependency scanning (OWASP Dependency-Check); patch CVEs.
- Rate limiting & CORS; lock down Actuator endpoints.
Production Deployment Strategies
A consolidated checklist for shipping Spring Boot to production safely.
Build & Package
Layered/multi-stage Docker image, pinned tags (git SHA), non-root, scanned.
Config
Externalized per env, profiles, secrets from a vault — never in the image.
Resilience
Health probes, graceful shutdown, ≥2 replicas, circuit breakers, autoscaling.
Observability
Actuator + Prometheus metrics, centralized logs, distributed tracing, alerts.
Data
Flyway/Liquibase migrations, ddl-auto=validate, backups, connection pooling.
Release
CI/CD, rolling / blue-green / canary, automated rollback.