Der Spickzettel zu Spring Boot 4 Grundlagen — Annotationen, Rangfolgen und Kurzformen zum Nachschlagen, wenn man weiß, dass es geht, aber nicht mehr genau wie. Maßgeblich und immer aktuell ist die Spring-Boot-Referenzdokumentation; hier steht die Auswahl, die im Alltag tatsächlich gebraucht wird.
Starter und Autokonfiguration
Vier Ebenen, die oft in einen Topf geworfen werden. Wer sie trennt, weiß jederzeit, an welcher Stelle einzugreifen ist.
| Ebene | Liefert | Überlässt Ihnen |
|---|---|---|
| Spring Framework | Bausteine und Programmiermodell | Auswahl und Konfiguration |
| Spring Boot | Vorauswahl und Startlogik | Die fachlichen Entscheidungen |
| Starter | Passende Abhängigkeiten im Bündel | Welche Fähigkeit Sie brauchen |
| Autokonfiguration | Fertig verdrahtete Komponenten | Das bewusste Abweichen davon |
Eine Vorgabe ändert man, indem man Abhängigkeiten tauscht — nicht, indem man gegen sie konfiguriert. Tomcat-Starter ausschließen, Jetty-Starter ergänzen, und der Servlet-Container ist gewechselt; Code braucht es dafür nicht.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
</parent>
Keine Versionsnummern zu verwalteten Abhängigkeiten schreiben — das Eltern-Projekt legt für jede eine erprobte Version fest.
Modul: Einführung in Spring Boot
Die Startklasse
@SpringBootApplication ist eine Meta-Annotation und wirkt wie drei einzelne:
| Annotation | Wirkung |
|---|---|
@SpringBootConfiguration | Erlaubt der Klasse, Bean-Methoden zu enthalten |
@ComponentScan | Sucht annotierte Klassen und registriert sie als Beans |
@EnableAutoConfiguration | Startet die Autokonfiguration |
Die Komponentensuche beginnt beim Paket der Startklasse. Beans außerhalb dieses Paketbaums werden nicht gefunden — die häufigste Ursache für fehlende Abhängigkeiten beim Start.
Modul: Einführung in Spring Boot
Konfiguration: Rangfolge der Quellen
Je spezifischer eine Quelle, desto stärker wiegt sie. Bei einem unerwarteten Wert nicht im Code suchen, sondern diese Liste von oben durchgehen.
| Quelle | Typische Verwendung |
|---|---|
| Kommandozeilenargument | Einmaliger Lauf, schnelle Gegenprobe |
| Umgebungsvariable | Betrieb im Container |
| Datei im Dateisystem | Umgebungsspezifische Einstellungen |
application.properties im Jar | Vorgaben für alle Umgebungen |
@Value("${radwerk.begruessung:Kein Text gesetzt}")
private String begruessung;
Ohne Vorgabewert nach dem Doppelpunkt startet die Anwendung nicht.
Umgebungsvariablen stehen groß mit Unterstrichen (RADWERK_BEGRUESSUNG); Spring
Boot übersetzt in Kleinschreibung mit Punkten.
Externe Dateien einbinden:
| Eigenschaft | Wirkung |
|---|---|
spring.config.location | Ersetzt die Datei im Jar vollständig |
spring.config.additional-location | Ergänzt sie, externe Werte haben Vorrang |
Modul: Konfigurationsverwaltung und Profile
Profile
Ein Profil ist nur ein Etikett — es gibt keine vordefinierten Namen mit eingebauter Bedeutung.
application.properties gemeinsam
application-dev.properties lokal
application-prod.properties produktiv
java -jar werkstatt.jar --spring.profiles.active=prod,metriken
Die Profildatei wird zusätzlich geladen und hat Vorrang: Gemeinsames einmal
in die schlichte Datei, nur Abweichendes in die Profildatei. @Profile schaltet
auch einzelne Beans profilabhängig.
Modul: Konfigurationsverwaltung und Profile
Parameterbindung im Controller
| Annotation | Quelle in der Anfrage | Beispiel |
|---|---|---|
@RequestParam | Abfrageparameter | /termine?filialeId=101 |
@PathVariable | Platzhalter im Pfad | /termine/501 |
@RequestBody | Rumpf der Anfrage | POST mit JSON |
Faustregel für den Entwurf: Zugriff über den Schlüssel gehört in den Pfad (er benennt eine Ressource), Suche nach anderen Kriterien in Abfrageparameter.
@RestController ist @Controller plus @ResponseBody — ohne den zweiten Teil
sucht Spring eine View, statt den Rückgabewert als Antwortrumpf zu schreiben.
Steht @RequestMapping an der Klasse, gilt sein Pfad als Basis aller Methoden.
Modul: RESTful APIs mit Spring Boot
Fehlerbehandlung
| Weg | Wirkung | Grenze |
|---|---|---|
ResponseEntity je Methode | Volle Kontrolle | Wiederholt sich überall |
@ExceptionHandler in der Klasse | Eine Stelle je Controller | Gilt nur dort |
@ControllerAdvice | Eine Stelle für alle | Braucht klare Regeln |
@ExceptionHandler(NoSuchElementException.class)
public ErrorResponse nichtGefunden(NoSuchElementException e) {
return ErrorResponse.create(e, HttpStatus.NOT_FOUND, e.getMessage());
}
Modul: RESTful APIs mit Spring Boot
Validierung
Drei Bausteine, und alle drei müssen sitzen — fehlt einer, wird stillschweigend nicht geprüft:
- Abhängigkeit
spring-boot-starter-validation @Validam Methodenparameter- Prüfannotationen am Record
public record AnmeldungAnfrage(
@NotNull(message = "Leistung ist erforderlich") Long leistungId,
@NotBlank(message = "Name darf nicht leer sein") String kundenname) {}
@NotNull verlangt einen Wert, @NotBlank zusätzlich einen nicht leeren Text.
Prüfdetails erscheinen ohne weiteres Zutun nicht in der Antwort.
Modul: RESTful APIs mit Spring Boot
API-Versionierung
Neu in Spring Boot 4: Die Version wird Teil der Zuordnung statt der Methodenlogik — mehrere Methoden dürfen denselben Pfad in verschiedenen Versionen bedienen.
| Weg | Beispiel | Bemerkung |
|---|---|---|
| Im Pfad | /v2/termine | Sofort sichtbar |
| Als Abfrageparameter | /termine?version=2 | Leicht zu setzen |
| Eigener Kopf | X-API-Version: 2 | Pfad bleibt sauber |
| Im Accept-Kopf | application/json;version=2 | Standardnah |
Modul: RESTful APIs mit Spring Boot
Spring Data: Schichten und Repositories
| Ebene | Was sie leistet | Beispiel |
|---|---|---|
| JDBC | Roher Zugriff auf die Datenbank | Treiber, SQL |
| JPA | Abbildung Objekt zu Tabelle | Hibernate |
| Spring Data JPA | Repositories ohne Implementierung | JpaRepository |
| Boot-Starter | Datenquelle und Transaktionen | starter-data-jpa |
public interface TerminRepository extends JpaRepository<Termin, Long> {
List<Termin> findByFilialeId(Long filialeId);
}
Erster Typparameter ist die Entität, zweiter der Typ ihres Schlüssels.
findAll und findById stammen aus den geerbten Schnittstellen; eigene Methoden
leitet Spring Data aus dem Namen ab — Namen sind hier Abfragen. Die
Implementierung entsteht beim Start und liegt nicht als Datei im Projekt.
Entitäten müssen veränderlich sein: @Entity, @Table, @Id,
@GeneratedValue, @Column, Beziehungen über @ManyToOne und @JoinColumn.
Records scheiden für JPA damit aus — für MongoDB nicht:
@Document
public record Anmeldung(@Id String id, Long leistungId, String kundenname) {}
public interface AnmeldungRepository extends MongoRepository<Anmeldung, String> {}
@Document stammt aus dem MongoDB-Paket, @Id hier aus
org.springframework.data.annotation — nicht aus JPA; ein falscher Import
sieht identisch aus und wirkt nicht.
Schema und Daten kommen aus schema.sql und data.sql in src/main/resources,
dazu spring.jpa.hibernate.ddl-auto=none — sonst legen Hibernate und Skript
dieselben Tabellen an. In Produktion gehört stattdessen ein Migrationswerkzeug
wie Flyway oder Liquibase davor.
Modul: Datenzugriff und Persistenz
Testzuschnitte
Der Zuschnitt entscheidet über Aussagekraft und Laufzeit — je schmaler, desto schneller.
| Annotation | Lädt | Werkzeug |
|---|---|---|
@WebMvcTest(X.class) | Einen Controller, kein Tomcat, keine Datenbank | MockMvc |
@DataJpaTest | H2 im Speicher plus Datenquelle | TestEntityManager |
@DataMongoTest | Dasselbe Muster für MongoDB | Repository |
@SpringBootTest | Die volle Anwendung | je nach Webumgebung |
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
Ohne RANDOM_PORT läuft auch @SpringBootTest gegen eine nachgebildete
Webumgebung. @DirtiesContext erzwingt einen frischen Kontext nach jeder
Testklasse — sonst bleibt die H2-Datenbank bestehen und die zweite Klasse
scheitert an bereits existierenden Tabellen.
@MockitoBean legt eine Attrappe an und registriert sie im Testkontext. Für
externe Systeme startet Testcontainers einen Container für die Dauer des Tests;
das Feld braucht @Container (meldet es JUnit) und @ServiceConnection
(übergibt die Verbindungsdaten an Spring Boot).
Modul: Spring-Boot-Anwendungen testen
Actuator-Endpunkte
| Endpunkt | Auskunft |
|---|---|
health | Läuft die Anwendung ordnungsgemäß |
metrics | Verbrauchs- und Durchsatzwerte |
loggers | Protokollierung ansehen und im Lauf ändern |
beans | Welche Beans im Kontext registriert sind |
env | Welche Konfigurationswerte tatsächlich gelten |
conditions | Welche Entscheidungen die Autokonfiguration traf |
mappings | Welche Anfrage zu welcher Methode führt |
Ohne Zutun ist nur health über HTTP erreichbar. Freischalten sparsam und mit
Zugriffsschutz davor — env verrät Konfigurationswerte:
management.endpoints.web.exposure.include=health,metrics,loggers
Metriken lassen sich über Etiketten aufschlüsseln:
/actuator/metrics/http.server.requests?tag=status:404. Sie zeigen den
Verlauf und brauchen dafür ein Ziel außerhalb der Anwendung.
Modul: Observability mit Actuator, Metriken und Logging
Auslieferung
./mvnw spring-boot:build-image
Baut ein Abbild ohne Dockerfile über Buildpacks, die es sinnvoll schichten.
Vorher die Java-Version des Plugins in der pom.xml setzen.
Unter Docker Compose finden Container einander über ihren Dienstnamen; feste Adressen hebeln das aus. Eine Abhängigkeit auf den Gesundheitscheck des anderen Dienstes verhindert sporadische Verbindungsfehler beim Start. Für Ausrollvorgänge ohne abgebrochene Anfragen:
server.shutdown=graceful
Modul: Deployment und Betrieb
Native Abbilder: Gewinn und Preis
| Aspekt | Gewinn | Preis |
|---|---|---|
| Startzeit | Deutlich kürzer | Längerer Bau |
| Speicher | Spürbar geringer | Weniger Spielraum |
| Reflection | — | Nicht ohne Weiteres |
| Konfiguration | — | Teils anderes Verhalten |
| Reife | — | Nach Einschätzung noch experimentell |
Lohnt bei vielen kurzlebigen Instanzen oder wenn Speicher unmittelbar Kosten verursacht — nicht als Gewohnheit für jede Anwendung.
Modul: Deployment und Betrieb
Web MVC oder WebFlux
| Frage | Spring Web MVC | Spring WebFlux |
|---|---|---|
| Programmierstil | Imperativ, vertraut | Reaktive Ströme, funktional |
| Ein- und Ausgabe | Blockierend | Nicht blockierend |
| Einarbeitung | Flach | Steil |
| Fehlersuche | Gewohnt | Deutlich mühsamer |
| Empfehlung | Der Regelfall | Nur bei belegtem Nutzen |
Modul: RESTful APIs mit Spring Boot
Typische Fallen
- Beans außerhalb des Paketbaums der Startklasse — die Komponentensuche findet sie nicht, und die Fehlermeldung nennt selten die Ursache.
- Versionsnummern zu verwalteten Abhängigkeiten hebeln die Abstimmung des Eltern-Projekts aus.
- Gegen eine Vorgabe konfigurieren, statt den Starter zu tauschen.
spring.config.locationstattadditional-location— alle Vorgaben aus dem Jar sind damit weg.- Umgebungsvariablen kleingeschrieben setzen und sich über die Wirkungslosigkeit wundern.
- Das aktive Profil fest ins Jar schreiben und die Auslieferung wieder umgebungsabhängig machen.
@Controllerstatt@RestController— der Endpunkt antwortet, aber mit leerem Rumpf.@Validam Parameter vergessen — die Prüfannotationen am Record bleiben wirkungslos, ohne Warnung.get()auf einem leerenOptional— ergibt Status 500, wo 404 richtig wäre.- Records als JPA-Entitäten scheitern an der geforderten Veränderlichkeit.
@Idaus dem falschen Paket bei MongoDB — sieht identisch aus, wirkt nicht.data.sqlohneschema.sql— das Datenskript läuft, bevor die Tabellen existieren.- Hibernates Schemaerzeugung in Produktion aktiv lassen.
- Alles als Integrationstest schreiben und die Rückmeldung so verlangsamen, dass niemand die Tests mehr laufen lässt.
@ServiceConnectionvergessen — der Container läuft, die Anwendung weiß nichts davon.- Alle Actuator-Endpunkte freigeben oder die Freigabeliste aus der Entwicklung mit ausliefern.
- Passwörter in eine ConfigMap statt in ein Secret schreiben.
- Die Java-Version im Build-Image-Plugin vergessen.
- Ohne Gesundheitscheck starten — sporadische Verbindungsfehler, die sich schlecht reproduzieren lassen.