Zum Hauptinhalt springen

Geführte Migration Spring Boot 3 → 4

Boot 4 ist weniger brutal als der Sprung von Boot 2 auf 3 — aber es bleibt ein Major Upgrade. Der bewährte Weg:


aktuelles Boot 3.x → neuestes Boot 3.5.x → Boot 4.x

Der Boot-4.0-Migrationsguide empfiehlt: zuerst auf die neueste 3.5.x, Deprecations aufräumen, Abhängigkeiten prüfen, dann auf das aktuelle Boot-4-Wartungsrelease.

Was am Ende stehen soll

  • App läuft auf Spring Boot 4.x
  • Dependencies passen zu Spring Framework 7.x
  • Keine entfernten Boot-3-APIs mehr im Code
  • Neue Starter bewusst gesetzt — nicht aus Versehen transitiv
  • Unit-, Slice- und Integrationstests grün
  • Dieselben operativen Endpunkte wie vorher in Produktion

Phase 0: Ist die App bereit?

Bevor du eine Versionsnummer anfasst.

PrüfpunktWarum
Bereits auf neuester Boot 3.5.xWeniger Baustellen beim Sprung auf 4.
Keine ignorierten Deprecation-WarnungenWas in Boot 3 deprecated ist, fehlt in Boot 4 oft ganz.
Java 17+ in CI und ProduktionMinimum für Boot 4. Für neue Services: lieber Java 21+.
Drittanbieter-Libs für Framework 7 / Jakarta EE 11Scheitern passiert oft am Ökosystem, nicht an Boot selbst.
Keine Abhängigkeit von EntferntemUndertow, reaktives Pulsar, Spring Session Hazelcast/MongoDB, Boot-Spock — weg. Siehe Entfernt in Boot 4.
Null-Safety-Tooling geprüftBoot 4 setzt auf JSpecify — Kotlin und Static Analysis können neue Fehler zeigen.
Tests für Startup, Web, Security, Persistenz, ObservabilitySchwache Integrationstests rächen sich bei Major Upgrades.

Phase 1: Zuerst Boot 3.5

Bringe die App auf die neueste 3.5-Linie, bevor du 4.x anfasst.

Maven:


<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.x</version>
</parent>

Gradle:


plugins {
id 'org.springframework.boot' version '3.5.x'
}

Dann:

  1. Komplette Testsuite laufen lassen.
  2. Warnungen zu deprecated APIs, Properties, Annotationen beheben.
  3. Dependency Tree prüfen — wer pinnt alte Spring-, Jakarta-, Jackson-, Hibernate-, Tomcat-, Jetty- oder Test-Versionen?
  4. Als eigene Migrations-Baseline committen.

Phase 2: Plattform-Baseline

BereichBoot 3.5Boot 4
Java-MinimumJava 17Java 17
EmpfohlenJava 21Java 21+
Spring Framework6.27.x
Jakarta EEEE 10EE 11
Servlet6.06.1
Kotlinfrühere 2.x2.2+
GraalVM Native22.3+25+
Gradle7.6+/8.x8.14+ oder 9

Java 17 reicht zum Start. Du musst nicht zuerst Java migrieren — aber in Produktion ist 21 meist die bessere Wahl. Details: System Requirements.

Phase 3: Boot-Version auf 4.x

Maven:


<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.x</version>
</parent>

Gradle:


plugins {
id 'org.springframework.boot' version '4.0.x'
}

./mvnw clean test
# oder
./gradlew clean test

Es wird rot. Das ist normal. Erstes Ziel: Fehler einordnen — Abhängigkeit, Quellcode, Property, Test oder Runtime.

Phase 4: Starter umbenennen und ergänzen

Boot 4 ist modularer. Alte Starter-Namen gibt es noch kurz, sind aber deprecated.

Schema:


spring-boot-<technologie>
spring-boot-starter-<technologie>
spring-boot-<technologie>-test
spring-boot-starter-<technologie>-test
Boot 3Boot 4
spring-boot-starter-webspring-boot-starter-webmvc
spring-boot-starter-web-servicesspring-boot-starter-webservices
spring-boot-starter-aopspring-boot-starter-aspectj
spring-boot-starter-oauth2-clientspring-boot-starter-security-oauth2-client

HTTP-Clients:

FallStarter
RestClient / RestTemplatespring-boot-starter-restclient
WebClient (reaktiv)spring-boot-starter-webclient

Klassischer Fehler: früher hat ein anderer Starter Flyway, Liquibase oder Test-Hilfen mitgebracht. Jetzt musst du explizit hinzufügen:


spring-boot-starter-flyway
spring-boot-starter-liquibase
spring-boot-starter-security-test
spring-boot-starter-data-jpa-test

Phase 5: Jackson 3

Viele Imports wechseln von com.fasterxml.jackson... nach tools.jackson.... Annotationen bleiben unter com.fasterxml.jackson.annotation.

Prüfen:

  • eigene Serializer/Deserializer
  • eigene ObjectMapper-Beans
  • JSON in Tests
  • Libs, die noch Jackson 2 brauchen
  • spring.jackson.*

Boot 4 konfiguriert JsonMapper und XmlMapper direkt. Eine generische ObjectMapper-Bean überschreibt den JSON-Mapper oft nicht mehr — nimm lieber eine JsonMapper-Bean.

Properties werden spezifischer:


# Boot 3
spring.jackson.read...
spring.jackson.write...

# Boot 4
spring.jackson.json.read...
spring.jackson.json.write...

Noch nicht Jackson-3-bereit? Übergangsbrücke (deprecated):


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-jackson2</artifactId>
</dependency>

Mehr: Jackson 3 in Spring, Boot-4-Migrationsguide.

Phase 6: Tests

@MockBean / @SpyBean@MockitoBean / @MockitoSpyBean


@MockBean
@SpyBean

wird zu:


@MockitoBean
@MockitoSpyBean

@SpringBootTest
class OrderServiceTest {

@MockitoBean
private PaymentService paymentService;
}

Kein blindes Suchen-Ersetzen — die neuen Annotationen gelten nicht überall, besonders nicht in manchen Test-Config-Klassen.

JSpecify

org.springframework.lang.Nullable → tendenziell org.jspecify.annotations.Nullable. Unter Boot 3 grüner Code kann unter Boot 4 neue Nullability-Fehler werfen — besonders Kotlin und Static Analysis. Mehr.

Explizite Test-Auto-Konfiguration

@SpringBootTest liefert MockMvc, TestRestTemplate und WebClient nicht mehr von selbst.

MockMvc:


@SpringBootTest
@AutoConfigureMockMvc
class ControllerTest {
}

Gegen laufenden Server:


@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class ApiIntegrationTest {
}

Neu: RestTestClient — MockMvc oder echter HTTP-Server.

Phase 7: Web und Server

  • Tomcat 11, Jetty 12.1, Servlet 6.1
  • Undertow ist weg — kein schneller Dependency-Tausch, sondern eigene Entscheidung
  • WAR auf externem Tomcat: spring-boot-starter-tomcat-runtime

Entfernt in Boot 4

Vor dem Upgrade prüfen, ob du das noch brauchst:

  • Undertow (embedded)
  • Reaktives Spring Pulsar
  • Unix-Startskripte in fully executable JARs
  • Spring Session Hazelcast / MongoDB
  • Boot-Spock-Integration
  • @MockBean, @SpyBean
  • Deprecated Boot-3-APIs, Klassen, Properties

Spring Security 7

Boot 4 bringt Security 7. Oft bricht Security, bevor Boot-spezifischer Code bricht. Wenn möglich: auf Security 6.5 noch unter Boot 3.5 vorbereiten (Preparing for 7.0), Rest nach dem Boot-4-Sprung (Migrating to 7.0).

OAuth2-Client-Starter aus Phase 4: spring-boot-starter-security-oauth2-client.

Die fünf häufigsten Stolpersteine

1. Lambda DSL für HttpSecurity ist Pflicht

.and()-Chaining funktioniert nicht mehr:


http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin
.loginPage("/login")
.permitAll()
);

Login/Auth verhält sich anders? Hier zuerst schauen. Configuration

2. PathPatternRequestMatcher statt Ant/MVC

AntPathRequestMatcher und MvcRequestMatcher sind weg. Achtung bei eigenen setFilterProcessingUrl(...), SwitchUserFilter, Servlet-Path-Prefix, JSP-Taglibs.

3. Method Security braucht -parameters

@PreAuthorize("@authz.check(#id)") setzt voraus, dass Parameternamen zur Laufzeit da sind. Framework 7 hat LocalVariableTableParameterNameDiscoverer entfernt.

4. OAuth2 JWT: typ-Validierung

Bei eigenem NimbusJwtDecoder wandert typ-Prüfung zu JwtTypeValidator. OAuth 2.0

5. Security-Serialisierung → Jackson 3

SecurityJackson2Modules / ObjectMapperSecurityJacksonModules / JsonMapper.Builder. Login, Remember-Me, OAuth2, persistierter Security Context explizit testen. Überschneidung mit Phase 5.

Security-Tests

Form-Login/Logout, CSRF-POSTs, OAuth2 Login/Resource Server, @PreAuthorize/@PostAuthorize, Session/Remember-Me über Neustart.

Phase 8: Daten und Persistenz

Upgrades u. a.: Hibernate 7.1, JPA 3.2, Validator 9, HikariCP 7, Flyway 11, Liquibase 5, Testcontainers 2, Kafka 4.1, MongoDB Driver 5.6.

Gezielt testen: Repository-Queries, JPQL/SQL, Mappings, Validation, Migrationen, Transaktionsgrenzen, Testcontainers.

Spring Batch: spring-boot-starter-batch nutzt standardmäßig ein In-Memory-Job-Repository. DB-Metadaten? → spring-boot-starter-batch-jdbc.

Ökosystem-Notizen:

Elasticsearch: RestClientRest5Client, Customizer: Rest5ClientBuilderCustomizer.

MongoDB: spring.data.mongodb.*spring.mongodb.*. UUID/BigDecimal ggf. explizit konfigurieren.

Redis: Observability stärker über Observation API — Dashboards und Tracing prüfen.

Phase 9: Properties

Properties-Migrator temporär:


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>

App starten, Diagnostik lesen, Properties fixen, Migrator wieder raus.

Beispiele:


# Boot 3 → Boot 4
spring.data.mongodb.* → spring.mongodb.*
management.tracing.enabled → management.tracing.export.enabled

Liveness/Readiness standardmäßig an:


/actuator/health/liveness
/actuator/health/readiness

Abschalten: management.endpoint.health.probes.enabled=false

Kleinigkeiten, die überraschen:

  • Logback default UTF-8
  • DevTools LiveReload aus
  • Optionale Maven-Deps nicht mehr im Uber-JAR
  • JDK-HTTP-Clients nutzen Virtual Threads bei spring.threads.virtual.enabled=true
  • Spring Retry nicht mehr von Boot versioniert

Phase 10: Neue Features — erst wenn stabil

Nicht Migrationsarbeit mit Feature-Adoption mischen.

FeatureKurzLink
HTTP Service ClientsClients für @HttpExchangeBlog
API-VersionierungMVC/WebFlux Auto-ConfigBlog
OpenTelemetrySDK + OTLPMigrationsguide
JSpecifyBessere Static AnalysisBlog

spring.mvc.apiversion...
spring.webflux.apiversion...

PR-Checkliste

  • Sauber auf neuester Boot 3.5.x
  • Deprecated Boot-3-APIs/Properties entfernt
  • Java, Kotlin, Gradle, GraalVM geprüft
  • Neue Starter inkl. Flyway, Liquibase, Test-Starter
  • Jackson 3, JsonMapper, ggf. spring-boot-jackson2
  • @MockBean/@SpyBean bewusst ersetzt
  • @SpringBootTest mit expliziter Client-Auto-Config
  • JSpecify/Nullability (Kotlin, Static Analysis)
  • Security 7 — Lambda DSL, Matcher, Method Security, JWT, Jackson
  • Spring Data 2025.1
  • Entferntes bestätigt weg (Undertow & Co.)
  • Daten-Libs getestet (ES, Mongo, Redis falls genutzt)
  • Batch-Job-Repository-Verhalten
  • Actuator, Tracing, Health Probes
  • Properties-Migrator gelaufen und entfernt
  • Produktions-Smoke-Test

Typische Fehler

SymptomUrsacheErster Schritt
Web-Klassen fehlenModularisierungwebmvc, restclient oder webclient explizit
Flyway/Liquibase läuft nichtTransitive Starter wegstarter-flyway / starter-liquibase
Slice-Test startet nichtTest-Starter fehltstarter-*-test
Jackson-Import rotPaketwechseltools.jackson.*
JSON-Config wirkungslosObjectMapper greift nichtJsonMapper-Bean
Mock-Tests rot@MockBean weg@MockitoBean, Platzierung prüfen
Kein MockMvc@SpringBootTest weniger magisch@AutoConfigureMockMvc
Kotlin/Null-Analyse neuJSpecifyorg.jspecify.annotations.*
Security kompiliert nichtLambda DSL.and() raus, Lambda-Stil
Auth-Regeln passen nichtPathPatternAnt/MVC-Matcher ersetzen
@PreAuthorize + #paramKeine Parameternamen-parameters
JWT abgelehnttyp-ValidierungJwtTypeValidator
Login nach Jackson kaputtSecurity Jackson 3SecurityJacksonModules testen
Queries andersData 2025.1 / Hibernate 7Release Notes / Migrationsguide
Batch-Metadaten fehlenIn-Memory-Defaultstarter-batch-jdbc
ES-Client kaputtRest5ClientCustomizer anpassen
Mongo-Config ignoriertPrefixspring.mongodb.*
Undertow rotEntferntTomcat oder Jetty
Health andersProbes default anGruppen prüfen/konfigurieren

Offizielle Referenzen

Spring Boot

Portfolio

Daten

Dieser Guide ergänzt die offiziellen Spring-Notizen — kritische Produktionsentscheidungen immer gegen die Docs für deine konkrete Boot-4.x-Version prüfen.