Spring Boot cheat sheet
A scannable Spring Boot reference: 19 short snippets across 13 topics, each linking back to the lesson it came from.
At a glance
| Topic | What it covers | |
|---|---|---|
| Project setup and your first controller | Spring Initializr produces the skeleton with a build file, a wrapper and a test already wired up. Choose the | lesson |
| REST controllers and dependency injection | The HTTP annotations you will use daily, DTOs at the boundary, and constructor injection done properly | lesson |
| Configuration, JPA data access and profiles | Layered properties, environment-specific profiles, and a repository layer with the traps called out | lesson |
| Request validation and global error handling | Annotation-based validation runs on the object that arrives from the network, not on your entities. Put the rules on a | lesson |
| JPA relationships, queries and pagination | A Page serialises to content, totalElements, totalPages and number. The count query is a real second query - for large | lesson |
| Schema migrations with Flyway and seed data | Set spring.jpa.hibernate.ddl-auto to validate and let Flyway own the schema. Hibernate then fails fast when the entity | lesson |
| Transactions, locking and concurrency | The retry must re-read the row inside the transaction, otherwise it retries with the same stale version and fails | lesson |
| Securing the API with Spring Security | Role checks alone are not authorization. Check ownership too: hasRole('USER') says the caller is logged in, not that | lesson |
| Testing Spring Boot applications | Full-context versus slice tests, MockMvc, @DataJpaTest, Testcontainers against a real database, and when to mock | lesson |
| Observability with Actuator, logging and metrics | Tag meters with low-cardinality dimensions such as status code or endpoint template. Never tag with a user id, an order | lesson |
| Caching, async processing and scheduling | Every instance of your service runs its own scheduler. Without a distributed lock, a nightly job runs once per replica | lesson |
| Packaging and deploying a Spring Boot service | Layered jars, Dockerfiles and buildpacks, externalised configuration, container-aware memory settings and safe rolling | lesson |
| Next steps: WebFlux, messaging and native images | Choosing reactive or servlet, using WebClient correctly, integrating Kafka, building a GraalVM native image, and where | lesson |
Quick snippets
Project setup and your first controller
Generating the project
# download from start.spring.io, or use your IDE wizard
unzip demo.zip -d demo
cd demo
./mvnw spring-boot:run # starts the app on http://localhost:8080
./mvnw test # runs the generated context test
./mvnw package # builds target/demo-0.0.1-SNAPSHOT.jar
java -jar target/demo-0.0.1-SNAPSHOT.jarFull lesson: Project setup and your first controller →
REST controllers and dependency injection
REST controllers
record CreateUser(@NotBlank String name, @Email String email) {}
record UserDto(long id, String name, String email) {
static UserDto from(User u) {
return new UserDto(u.getId(), u.getName(), u.getEmail());
}
}Full lesson: REST controllers and dependency injection →
Configuration, JPA data access and profiles
Configuration and profiles
# src/main/resources/application.properties
spring.application.name=demo
server.port=8080
spring.jpa.open-in-view=false
app.greeting=Hello
Configuration and profiles
# src/main/resources/application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/demo
username: demo
password: ${DB_PASSWORD} # read from the environment, never committed
jpa:
hibernate:
ddl-auto: validate
Configuration and profiles
@Component
@ConfigurationProperties(prefix = "app")
class AppProperties {
private String greeting = "";
// getters and setters
}
@Configuration
@Profile("prod")
class ProdCacheConfig {
// only active when the prod profile is on
}Full lesson: Configuration, JPA data access and profiles →
Request validation and global error handling
Validating the boundary
public record CreateBookRequest(
@NotBlank String title,
@NotBlank @Size(max = 64) String author,
@ISBN String isbn,
@PositiveOrZero Integer copies,
@Email String contactEmail,
@Valid AddressRequest address) {}
@PostMapping("/books")
public ResponseEntity<BookResponse> create(@Valid @RequestBody CreateBookRequest req) {
return ResponseEntity.status(HttpStatus.CREATED).body(service.create(req));
}Full lesson: Request validation and global error handling →
JPA relationships, queries and pagination
Pagination and sorting from the controller
@GetMapping("/books")
Page<BookSummary> list(@PageableDefault(size = 20, sort = "title") Pageable pageable) {
return repo.findSummaries(pageable);
}
// GET /books?page=0&size=20&sort=publishedAt,descFull lesson: JPA relationships, queries and pagination →
Schema migrations with Flyway and seed data
Reference data and test seeding
-- R__seed_countries.sql (repeatable: re-runs when the file changes)
insert into country (code, name)
values ('DE', 'Germany'), ('FR', 'France'), ('GB', 'United Kingdom')
on conflict (code) do update set name = excluded.name;Full lesson: Schema migrations with Flyway and seed data →
Transactions, locking and concurrency
Optimistic and pessimistic locking
@Retryable(retryFor = OptimisticLockingFailureException.class,
maxAttempts = 3, backoff = @Backoff(delay = 50, multiplier = 2))
@Transactional
public void adjust(Long id, BigDecimal delta) { /* re-read inside the retry */ }Full lesson: Transactions, locking and concurrency →
Securing the API with Spring Security
Method security and ownership checks
@PreAuthorize("hasRole('ADMIN') or #ownerId == authentication.name")
public Order getOrder(String ownerId, Long orderId) { ... }
@PostAuthorize("returnObject.owner == authentication.name")
public Order load(Long id) { ... }
@PreAuthorize("@perm.canEdit(authentication, #id)")
public void update(Long id, UpdateDto dto) { ... }Full lesson: Securing the API with Spring Security →
Testing Spring Boot applications
Integration tests against a real database
// transaction boundary check in a @SpringBootTest
@Test
void rollbackOnFailure() {
assertThatThrownBy(() -> service.transferWithoutFunds(1L, 2L, HUNDRED))
.isInstanceOf(IllegalStateException.class);
assertThat(accounts.balanceOf(1L)).isEqualByComparingTo(TEN);
}
What to assert and what to mock
@TestConfiguration
class TestClock {
@Bean Clock clock() { return Clock.fixed(Instant.parse("2026-01-01T00:00:00Z"), ZoneOffset.UTC); }
}Full lesson: Testing Spring Boot applications →
Observability with Actuator, logging and metrics
Logging that survives production
logging:
level:
root: INFO
com.example.orders: DEBUG
org.hibernate.SQL: WARN
pattern:
console: '{"ts":"%d{yyyy-MM-dd''T''HH:mm:ss.SSSXXX}","level":"%p","logger":"%c{1.}","msg":"%m"}%n'Full lesson: Observability with Actuator, logging and metrics →
Caching, async processing and scheduling
Async work with a real executor
@Async("mailExecutor")
public CompletableFuture<Void> sendReceipt(Order order) {
mailer.send(order);
return CompletableFuture.completedFuture(null);
}
Scheduling in a multi-instance world
@Scheduled(cron = "0 */15 * * * *", zone = "UTC")
@SchedulerLock(name = "refreshCatalog") // ShedLock: one node at a time
public void refreshCatalog() { catalog.reload(); }
@Scheduled(fixedDelayString = "${jobs.reconcile.delay:PT5M}")
public void reconcile() { ... }Full lesson: Caching, async processing and scheduling →
Packaging and deploying a Spring Boot service
Building the artefact
# layered jar: dependencies change rarely, code changes often
./gradlew bootJar
java -Djarmode=tools -jar build/libs/orders-0.0.1.jar extract --destination build/extracted
# inspect the layers
unzip -l build/libs/orders-0.0.1.jar | head -20
# run with an external config file and an explicit profile
java -jar orders.jar --spring.profiles.active=prod \
--spring.config.additional-location=file:/etc/orders/
A production Dockerfile
FROM eclipse-temurin:21-jre-alpine AS runtime
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY --chown=app:app build/libs/*.jar app.jar
USER app
EXPOSE 8080
ENV JAVA_TOOL_OPTIONS="-XX:MaxRAMPercentage=75.0 -XX:+ExitOnOutOfMemoryError"
ENTRYPOINT ["java","-jar","/app/app.jar"]
Startup, probes and rollout
# Kubernetes excerpt
livenessProbe:
httpGet: { path: /internal/health/liveness, port: 8081 }
initialDelaySeconds: 60
failureThreshold: 3
readinessProbe:
httpGet: { path: /internal/health/readiness, port: 8081 }
periodSeconds: 5
lifecycle:
preStop:
exec: { command: ["sh","-c","sleep 5"] } # let the LB deregister firstFull lesson: Packaging and deploying a Spring Boot service →
Next steps: WebFlux, messaging and native images
Native images
./gradlew nativeCompile # via GraalVM
# or a container build
./gradlew bootBuildImage --imageName=orders-native -Pnative
# run it
./build/native/nativeCompile/orders
# typical result: ~100 MB RSS, 50-100 ms to first responseFull lesson: Next steps: WebFlux, messaging and native images →
FAQ
Is this Spring Boot cheat sheet free to use?
Where do the examples come from?
How do I go deeper than a cheat sheet?
Related cheat sheets
Last refreshed 2026-09-27.