Skip to main content

Spring

Keycloak with Spring Boot 4.1: Roles, Resource Server and Admin API

Keycloak 26.8 with Spring Boot 4.1 and Spring Security 7.1, tested against a real Keycloak: why roles are silently ignored, how a missing audience or a different host turns a valid token into a 401, method security, and managing users with the Keycloak admin client.

RestClient vs WebClient vs HTTP Interface Clients in Spring Boot 4.1: Which to Use

The same API called three ways on Spring Boot 4.1.1 and Spring Framework 7.0.9, measured: 10 parallel calls on platform threads, virtual threads and WebClient, the different exception types each client throws (even behind the same HTTP interface), timeouts, and the surprise that a plain RestClient runs on Reactor Netty when the WebClient starter is present. Five runnable Java files and a decision flowchart.

Multi-Factor Authentication in Spring Security 7 with @EnableMultiFactorAuthentication

Password plus one-time token on Spring Boot 4.1.1 and Spring Security 7.1.1: FactorGrantedAuthority, @EnableMultiFactorAuthentication, step-up authentication for /admin with a freshness window, the real redirect URLs for a missing or expired factor, and the trap where a hand-built step-up factory silently drops the first factor. Ten runnable Java files.

OAuth2 Login with Google and GitHub in Spring Boot 4.1

Sign in with Google and GitHub using oauth2Login on Spring Boot 4.1.1 and Spring Security 7.1.1: the redirects the app really builds, mapping OIDC and GitHub users to local accounts without keying on email, a 401 trap for non-browser clients, and an SPA plus backend setup with CORS, CSRF and logout. Five runnable Java files to download.

Spring Boot Docker Compose Support: Real Containers for Local Development

Testcontainers (used throughout earlier posts in this series) is for tests: start a container, run assertions, tear it down, all inside the test JVM's lifecycle. Spring Boot's Docker Compose support solves a neighbouring problem — local development. Run the app normally, with a compose.yaml next to it, and Spring Boot starts the declared containers itself, wires up a real connection to them, and stops them again when the app exits. No spring.datasource.* property anywhere, and no manual docker compose up either. This post proves that end to end: a real docker compose up actually ran, a real Postgres container came up on a real (non-default) host port, a repository backed by a plain JdbcTemplate read and wrote through it, and — checked after the JVM exited, not assumed — the container actually stopped again. Versions used in this post. Spring Boot 4.1.1 · Spring Framework 7.0.9 · PostgreSQL JDBC driver 42.7.13 · postgres:17-alpine · Docker 29.8.2 · Docker Compose v5.5.1 · JDK 25 (Temurin). Confirmed via mvn dependency:tree and the real docker/docker compose CLI versions on the machine that ran this post's tests. This demo is small enough that it doesn't warrant its own repository module — every file is linked for download right where it's discussed below.

Structured Logging in Spring Boot 4: SLF4J Fluent API, MDC, and Custom Formatters

A human-readable log line is great for a terminal and terrible for a log aggregator, which has to regex-scrape fields back out of it. Structured logging flips that: write one JSON object per line instead, with fields as real JSON members from the start. Spring Boot 4 ships this as a built-in feature — no Logstash encoder dependency, no hand-rolled JSON layout — and this post builds a small service around it: one line enabled via a property, SLF4J's fluent API and MDC both landing as real JSON fields with zero extra code, and a custom formatter for when none of the built-in formats fit. Everything below was run for real: a Spring Boot context actually bootstrapped with logging.structured.format.console=ecs in effect, its console output captured and asserted on line by line, not assumed from the reference docs. Versions used in this post. Spring Boot 4.1.1 · Spring Framework 7.0.9 · Logback 1.5.38 · SLF4J 2.0.18 · JDK 25 (Temurin). Confirmed via mvn dependency:tree on spring-boot-starter alone — no web starter, no JSON library anywhere on the classpath. This demo is small enough that it doesn't warrant its own repository module — every source file is linked for download right where it's discussed below.

Apache Camel 4 on Spring Boot: Content-Based Routing and Dead-Letter Handling

Apache Camel's whole pitch is that integration logic — where a message goes, what happens when processing it fails — is declared once in a route, not scattered across try/catch blocks and if-statements. This post builds a small order-intake route on Camel 4 and Spring Boot 4: content-based routing on a header, and a redelivery policy that retries a failing message twice before giving up and shunting it to a dead-letter endpoint. The route logic itself turned out to be the easy part. The real content here is three things that only showed up by actually running it: confirming Camel 4 resolves cleanly against Spring Boot 4.1's dependencies at all, a genuinely useful testability trick (routing to property-placeholder endpoints so a test can swap in mocks without touching the route), and a sneaky test-isolation bug in that same trick's test harness. Versions used in this post. Spring Boot 4.1.1 · Apache Camel 4.22.1 (camel-spring-boot-bom) · JDK 25 (Temurin). Camel 4.22.1 was the latest release on Maven Central at the time of writing, checked against the real maven-metadata.xml rather than assumed, and mvn dependency:tree confirmed it pulls in Spring Boot 4.1.1 and Spring Framework 7.0.9 with no version conflicts. This demo is small enough that it doesn't warrant its own repository module — every source file is linked for download right where it's discussed below.