Spring Boot ist das mit Abstand populärste Framework für REST APIs in der Java-Welt — und das aus gutem Grund. Laut der JetBrains Developer Survey 2025 nutzen 74% aller Java-Entwickler Spring Boot für Backend-Anwendungen. In deutschen Unternehmen liegt der Anteil sogar bei über 80%, getrieben durch SAP, Deutsche Bank, Allianz und den industriellen Mittelstand.
Dieser Leitfaden zeigt Ihnen in 7 konkreten Schritten, wie Sie eine produktionsreife REST API mit Spring Boot 3.4 und Java 21 erstellen. Jeder Schritt enthält vollständigen, copy-paste-fähigen Code. Am Ende haben Sie eine funktionierende API mit CRUD-Endpunkten, Validierung, Fehlerbehandlung, OpenAPI-Dokumentation, Tests und Docker-Deployment.
Voraussetzungen
Bevor wir starten, stellen Sie sicher, dass folgende Tools installiert sind:
- Java 21 (LTS):
java -versionsollte 21.x anzeigen. Download: adoptium.net - Maven 3.9+ oder Gradle 8.x: Wir verwenden Maven in diesem Tutorial.
- IDE: IntelliJ IDEA (empfohlen) oder VS Code mit Java Extension Pack.
- Docker Desktop: Für Schritt 7 (Deployment). Optional für die ersten 6 Schritte.
Die 7 Schritte im Überblick
Schritt 1: Spring Boot Projekt mit Spring Initializr erstellen
Der schnellste Weg zu einem neuen Spring-Boot-Projekt führt über Spring Initializr. Sie können das Projekt entweder über die Web-Oberfläche oder direkt per cURL erstellen.
Option A: Web-Oberfläche (start.spring.io)
Konfigurieren Sie folgende Einstellungen:
- Project: Maven
- Language: Java
- Spring Boot: 3.4.x (neueste stabile Version)
- Group:
de.meinefirma - Artifact:
produkt-api - Java: 21
- Dependencies: Spring Web, Spring Data JPA, H2 Database, Validation, Spring Boot DevTools
Option B: cURL (Terminal)
curl https://start.spring.io/starter.zip \
-d type=maven-project \
-d language=java \
-d bootVersion=3.4.1 \
-d groupId=de.meinefirma \
-d artifactId=produkt-api \
-d name=produkt-api \
-d javaVersion=21 \
-d dependencies=web,data-jpa,h2,validation,devtools \
-o produkt-api.zip
unzip produkt-api.zip -d produkt-api
cd produkt-apiNach dem Entpacken haben Sie folgende Projektstruktur:
produkt-api/
├── src/
│ ├── main/
│ │ ├── java/de/meinefirma/produktapi/
│ │ │ └── ProduktApiApplication.java
│ │ └── resources/
│ │ └── application.properties
│ └── test/
│ └── java/de/meinefirma/produktapi/
│ └── ProduktApiApplicationTests.java
├── pom.xml
└── mvnwStarten Sie die Anwendung mit ./mvnw spring-boot:run. Wenn Sie auf http://localhost:8080 eine 404-Seite sehen, funktioniert alles — es gibt nur noch keine Endpunkte.
Schritt 2: Datenmodell und JPA-Entities definieren
Wir bauen eine Produkt-API — ein klassisches Beispiel, das sich auf jede Domäne übertragen lässt. Erstellen Sie die Entity-Klasse Produkt.java:
package de.meinefirma.produktapi.model;
import jakarta.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Entity
@Table(name = "produkte")
public class Produkt {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 200)
private String name;
@Column(length = 2000)
private String beschreibung;
@Column(nullable = false, precision = 10, scale = 2)
private BigDecimal preis;
@Column(nullable = false)
private String kategorie;
@Column(nullable = false)
private Integer bestand;
@Column(name = "erstellt_am", updatable = false)
private LocalDateTime erstelltAm;
@Column(name = "aktualisiert_am")
private LocalDateTime aktualisiertAm;
@PrePersist
protected void onCreate() {
erstelltAm = LocalDateTime.now();
aktualisiertAm = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
aktualisiertAm = LocalDateTime.now();
}
// Konstruktoren
public Produkt() {}
public Produkt(String name, String beschreibung,
BigDecimal preis, String kategorie, Integer bestand) {
this.name = name;
this.beschreibung = beschreibung;
this.preis = preis;
this.kategorie = kategorie;
this.bestand = bestand;
}
// Getter und Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getBeschreibung() { return beschreibung; }
public void setBeschreibung(String beschreibung) {
this.beschreibung = beschreibung;
}
public BigDecimal getPreis() { return preis; }
public void setPreis(BigDecimal preis) { this.preis = preis; }
public String getKategorie() { return kategorie; }
public void setKategorie(String kategorie) {
this.kategorie = kategorie;
}
public Integer getBestand() { return bestand; }
public void setBestand(Integer bestand) { this.bestand = bestand; }
public LocalDateTime getErstelltAm() { return erstelltAm; }
public LocalDateTime getAktualisiertAm() { return aktualisiertAm; }
}Konfigurieren Sie die H2-Datenbank in application.properties:
# Datenbank-Konfiguration
spring.datasource.url=jdbc:h2:mem:produktdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
# Server
server.port=8080Warum H2? Für die Entwicklung ist eine In-Memory-Datenbank ideal — kein Setup nötig, die Konsole unter /h2-console ermöglicht SQL-Debugging. Für Produktion ersetzen Sie H2 durch PostgreSQL oder MySQL (nur die application.properties ändern).
Schritt 3: Repository-Schicht mit Spring Data JPA implementieren
Spring Data JPA generiert die gesamte CRUD-Logik automatisch. Sie müssen lediglich ein Interface definieren:
package de.meinefirma.produktapi.repository;
import de.meinefirma.produktapi.model.Produkt;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.math.BigDecimal;
import java.util.List;
@Repository
public interface ProduktRepository extends JpaRepository<Produkt, Long> {
// Derived Query: Spring generiert SQL automatisch
List<Produkt> findByKategorie(String kategorie);
List<Produkt> findByNameContainingIgnoreCase(String name);
List<Produkt> findByPreisBetween(BigDecimal min, BigDecimal max);
// Custom JPQL-Query
@Query("SELECT p FROM Produkt p WHERE p.bestand < :schwelle")
List<Produkt> findNiedrigerBestand(Integer schwelle);
// Statistik
@Query("SELECT COUNT(p) FROM Produkt p WHERE p.kategorie = :kategorie")
long zaehleNachKategorie(String kategorie);
}Das ist der gesamte Datenzugriffscode. Spring Data JPA generiert die Implementierung zur Laufzeit. Die Methode findByKategorie wird automatisch zu SELECT * FROM produkte WHERE kategorie = ? übersetzt. Für komplexere Abfragen nutzen Sie @Query mit JPQL.
Schritt 4: REST-Controller mit CRUD-Endpunkten erstellen
Jetzt verbinden wir alles in einem REST-Controller. Wir folgen dem Service-Pattern: Controller → Service → Repository.
Zuerst der Service:
package de.meinefirma.produktapi.service;
import de.meinefirma.produktapi.model.Produkt;
import de.meinefirma.produktapi.repository.ProduktRepository;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
@Service
public class ProduktService {
private final ProduktRepository repository;
public ProduktService(ProduktRepository repository) {
this.repository = repository;
}
public List<Produkt> alleProdukte() {
return repository.findAll();
}
public Produkt produktNachId(Long id) {
return repository.findById(id)
.orElseThrow(() -> new ProduktNichtGefundenException(
"Produkt mit ID " + id + " nicht gefunden"));
}
public Produkt erstellen(Produkt produkt) {
return repository.save(produkt);
}
public Produkt aktualisieren(Long id, Produkt details) {
Produkt produkt = produktNachId(id);
produkt.setName(details.getName());
produkt.setBeschreibung(details.getBeschreibung());
produkt.setPreis(details.getPreis());
produkt.setKategorie(details.getKategorie());
produkt.setBestand(details.getBestand());
return repository.save(produkt);
}
public void loeschen(Long id) {
Produkt produkt = produktNachId(id);
repository.delete(produkt);
}
public List<Produkt> nachKategorie(String kategorie) {
return repository.findByKategorie(kategorie);
}
public List<Produkt> suchen(String name) {
return repository.findByNameContainingIgnoreCase(name);
}
}Die Custom Exception:
package de.meinefirma.produktapi.service;
public class ProduktNichtGefundenException extends RuntimeException {
public ProduktNichtGefundenException(String nachricht) {
super(nachricht);
}
}Und der REST-Controller:
package de.meinefirma.produktapi.controller;
import de.meinefirma.produktapi.model.Produkt;
import de.meinefirma.produktapi.service.ProduktService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/v1/produkte")
public class ProduktController {
private final ProduktService service;
public ProduktController(ProduktService service) {
this.service = service;
}
@GetMapping
public List<Produkt> alleProdukte() {
return service.alleProdukte();
}
@GetMapping("/{id}")
public ResponseEntity<Produkt> produktNachId(@PathVariable Long id) {
return ResponseEntity.ok(service.produktNachId(id));
}
@PostMapping
public ResponseEntity<Produkt> erstellen(@RequestBody Produkt produkt) {
Produkt gespeichert = service.erstellen(produkt);
return ResponseEntity.status(HttpStatus.CREATED).body(gespeichert);
}
@PutMapping("/{id}")
public ResponseEntity<Produkt> aktualisieren(
@PathVariable Long id, @RequestBody Produkt details) {
return ResponseEntity.ok(service.aktualisieren(id, details));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> loeschen(@PathVariable Long id) {
service.loeschen(id);
return ResponseEntity.noContent().build();
}
@GetMapping("/kategorie/{kategorie}")
public List<Produkt> nachKategorie(@PathVariable String kategorie) {
return service.nachKategorie(kategorie);
}
@GetMapping("/suche")
public List<Produkt> suchen(@RequestParam String name) {
return service.suchen(name);
}
}Testen Sie die API mit cURL:
# Produkt erstellen
curl -X POST http://localhost:8080/api/v1/produkte \
-H "Content-Type: application/json" \
-d '{"name":"MacBook Pro 16","beschreibung":"Apple M4 Max, 64GB RAM","preis":4299.00,"kategorie":"Laptops","bestand":25}'
# Alle Produkte abrufen
curl http://localhost:8080/api/v1/produkte
# Produkt nach ID
curl http://localhost:8080/api/v1/produkte/1
# Suchen
curl "http://localhost:8080/api/v1/produkte/suche?name=macbook"Schritt 5: Validierung, Fehlerbehandlung und DTOs hinzufügen
Produktionsreife APIs validieren Eingaben und geben strukturierte Fehlermeldungen zurück. Wir verwenden Bean Validation (Jakarta Validation) und trennen Request-DTOs von Entities.
Erstellen Sie das Request-DTO als Java Record:
package de.meinefirma.produktapi.dto;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
public record ProduktRequest(
@NotBlank(message = "Name darf nicht leer sein")
@Size(min = 2, max = 200, message = "Name muss 2-200 Zeichen lang sein")
String name,
@Size(max = 2000, message = "Beschreibung darf max. 2000 Zeichen lang sein")
String beschreibung,
@NotNull(message = "Preis ist erforderlich")
@DecimalMin(value = "0.01", message = "Preis muss mindestens 0.01 sein")
@DecimalMax(value = "999999.99", message = "Preis darf max. 999999.99 sein")
BigDecimal preis,
@NotBlank(message = "Kategorie darf nicht leer sein")
String kategorie,
@NotNull(message = "Bestand ist erforderlich")
@Min(value = 0, message = "Bestand darf nicht negativ sein")
Integer bestand
) {}Der globale Exception-Handler fängt alle Fehler ab und gibt einheitliche JSON-Antworten zurück:
package de.meinefirma.produktapi.exception;
import de.meinefirma.produktapi.service.ProduktNichtGefundenException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.*;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ProduktNichtGefundenException.class)
public ResponseEntity<Map<String, Object>> handleNichtGefunden(
ProduktNichtGefundenException ex) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("zeitstempel", LocalDateTime.now());
body.put("status", 404);
body.put("fehler", "Nicht gefunden");
body.put("nachricht", ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidierung(
MethodArgumentNotValidException ex) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("zeitstempel", LocalDateTime.now());
body.put("status", 400);
body.put("fehler", "Validierungsfehler");
List<Map<String, String>> fehler = ex.getBindingResult()
.getFieldErrors().stream()
.map(f -> Map.of(
"feld", f.getField(),
"nachricht", Objects.requireNonNullElse(
f.getDefaultMessage(), "Ungültiger Wert")
)).toList();
body.put("details", fehler);
return ResponseEntity.badRequest().body(body);
}
}Aktualisieren Sie den Controller, um @Valid und das DTO zu verwenden:
@PostMapping
public ResponseEntity<Produkt> erstellen(
@Valid @RequestBody ProduktRequest request) {
Produkt produkt = new Produkt(
request.name(),
request.beschreibung(),
request.preis(),
request.kategorie(),
request.bestand()
);
Produkt gespeichert = service.erstellen(produkt);
return ResponseEntity.status(HttpStatus.CREATED).body(gespeichert);
}Jetzt erhalten Sie bei ungültigen Eingaben strukturierte Fehlermeldungen:
{
"zeitstempel": "2026-06-07T10:30:00",
"status": 400,
"fehler": "Validierungsfehler",
"details": [
{ "feld": "name", "nachricht": "Name darf nicht leer sein" },
{ "feld": "preis", "nachricht": "Preis muss mindestens 0.01 sein" }
]
}Schritt 6: API-Dokumentation mit SpringDoc OpenAPI generieren
Professionelle APIs brauchen Dokumentation. SpringDoc OpenAPI generiert automatisch eine interaktive Swagger-UI aus Ihren Controller-Annotationen.
Fügen Sie die Dependency in pom.xml hinzu:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.4</version>
</dependency>Konfigurieren Sie OpenAPI in application.properties:
# OpenAPI
springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
springdoc.swagger-ui.operationsSorter=methodErgänzen Sie den Controller mit OpenAPI-Annotationen für detaillierte Beschreibungen:
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
@Tag(name = "Produkte", description = "CRUD-Operationen für Produkte")
@RestController
@RequestMapping("/api/v1/produkte")
public class ProduktController {
@Operation(
summary = "Alle Produkte abrufen",
description = "Gibt eine Liste aller Produkte zurück"
)
@ApiResponse(responseCode = "200", description = "Erfolgreiche Abfrage")
@GetMapping
public List<Produkt> alleProdukte() {
return service.alleProdukte();
}
@Operation(summary = "Produkt nach ID abrufen")
@ApiResponse(responseCode = "200", description = "Produkt gefunden")
@ApiResponse(responseCode = "404", description = "Produkt nicht gefunden")
@GetMapping("/{id}")
public ResponseEntity<Produkt> produktNachId(
@Parameter(description = "Produkt-ID") @PathVariable Long id) {
return ResponseEntity.ok(service.produktNachId(id));
}
}Starten Sie die Anwendung und öffnen Sie http://localhost:8080/swagger-ui.html. Sie sehen eine vollständige, interaktive API-Dokumentation mit Try-it-out-Funktion — ohne eine einzige Zeile manueller Dokumentation.
Spring Boot REST API: Schichtarchitektur
Schritt 7: Tests schreiben und in Docker deployen
Professionelle APIs werden getestet und containerisiert. Wir schreiben Unit-Tests für den Service und Integrationstests für den Controller.
Unit-Test für den Service (JUnit 5 + Mockito)
package de.meinefirma.produktapi.service;
import de.meinefirma.produktapi.model.Produkt;
import de.meinefirma.produktapi.repository.ProduktRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.util.Optional;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class ProduktServiceTest {
@Mock
private ProduktRepository repository;
@InjectMocks
private ProduktService service;
@Test
void sollteProduktNachIdFinden() {
// Given
Produkt produkt = new Produkt("Laptop", "Test",
new BigDecimal("999.99"), "Elektronik", 10);
produkt.setId(1L);
when(repository.findById(1L)).thenReturn(Optional.of(produkt));
// When
Produkt ergebnis = service.produktNachId(1L);
// Then
assertThat(ergebnis.getName()).isEqualTo("Laptop");
assertThat(ergebnis.getPreis())
.isEqualByComparingTo(new BigDecimal("999.99"));
verify(repository, times(1)).findById(1L);
}
@Test
void sollteExceptionWerfenWennNichtGefunden() {
// Given
when(repository.findById(99L)).thenReturn(Optional.empty());
// When & Then
assertThatThrownBy(() -> service.produktNachId(99L))
.isInstanceOf(ProduktNichtGefundenException.class)
.hasMessageContaining("99");
}
@Test
void sollteNeuesProduktErstellen() {
// Given
Produkt neuesProdukt = new Produkt("Monitor", "27 Zoll 4K",
new BigDecimal("549.00"), "Monitore", 50);
when(repository.save(neuesProdukt)).thenReturn(neuesProdukt);
// When
Produkt gespeichert = service.erstellen(neuesProdukt);
// Then
assertThat(gespeichert.getName()).isEqualTo("Monitor");
verify(repository).save(neuesProdukt);
}
}Integrationstest für den Controller
package de.meinefirma.produktapi.controller;
import de.meinefirma.produktapi.model.Produkt;
import de.meinefirma.produktapi.repository.ProduktRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.math.BigDecimal;
import static org.assertj.core.api.Assertions.*;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProduktControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private ProduktRepository repository;
@BeforeEach
void setUp() {
repository.deleteAll();
}
@Test
void sollteProduktErstellenUndAbrufen() {
// Erstellen
Produkt produkt = new Produkt("Tastatur", "Mechanisch",
new BigDecimal("149.99"), "Zubehör", 100);
ResponseEntity<Produkt> createResponse =
restTemplate.postForEntity("/api/v1/produkte",
produkt, Produkt.class);
assertThat(createResponse.getStatusCode())
.isEqualTo(HttpStatus.CREATED);
assertThat(createResponse.getBody()).isNotNull();
assertThat(createResponse.getBody().getId()).isNotNull();
// Abrufen
Long id = createResponse.getBody().getId();
ResponseEntity<Produkt> getResponse =
restTemplate.getForEntity("/api/v1/produkte/" + id,
Produkt.class);
assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(getResponse.getBody().getName()).isEqualTo("Tastatur");
}
}Tests ausführen: ./mvnw test
Docker-Deployment mit Multi-Stage Build
Erstellen Sie ein Dockerfile im Projektroot:
# Stage 1: Build
FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY pom.xml .
COPY mvnw .
COPY .mvn .mvn
RUN ./mvnw dependency:resolve
COPY src src
RUN ./mvnw package -DskipTests
# Stage 2: Run
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]Und eine docker-compose.yml für Produktion mit PostgreSQL:
version: '3.9'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/produktdb
- SPRING_DATASOURCE_USERNAME=postgres
- SPRING_DATASOURCE_PASSWORD=sicheres-passwort
- SPRING_JPA_DATABASE_PLATFORM=org.hibernate.dialect.PostgreSQLDialect
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: produktdb
POSTGRES_PASSWORD: sicheres-passwort
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
volumes:
pgdata:Starten Sie alles mit:
docker compose up --build -d
# API testen
curl http://localhost:8080/api/v1/produkte
# Logs ansehen
docker compose logs -f appZusammenfassung: Ihre REST API ist produktionsbereit
Sie haben in 7 Schritten eine vollständige REST API mit Spring Boot erstellt:
- Projekt erstellt mit Spring Initializr (Java 21, Spring Boot 3.4)
- Datenmodell definiert mit JPA-Entity und Lifecycle-Callbacks
- Repository implementiert mit Spring Data JPA und Custom Queries
- CRUD-Controller gebaut mit RESTful-Endpunkten und ResponseEntity
- Validierung hinzugefügt mit Bean Validation, DTOs und globalem Error-Handler
- API dokumentiert mit SpringDoc OpenAPI und Swagger-UI
- Tests geschrieben (Unit + Integration) und Docker-Deployment konfiguriert
Die API ist bereit für den nächsten Schritt: Authentifizierung mit Spring Security und JWT, Caching mit Redis, Rate Limiting, oder die Migration auf eine reaktive Architektur mit Spring WebFlux.
Spring-Boot-Entwickler für Ihr Team?
Wir helfen deutschen Unternehmen, erfahrene Java/Spring-Boot-Entwickler in 21 Tagen einzustellen. Zugang zu 500+ vorgeprüften Backend-Profilen in DACH. Senior-Level ab €78.000.
30-Minuten-Beratung buchen →Verwandte Artikel
- React + TypeScript Webanwendung erstellen — 7 Schritte für Anfänger
- CI/CD-Pipeline für KI-Projekte mit GitHub Actions — 7 Schritte
- Discord Bot mit Python programmieren — 7 Schritte
- Java-Entwickler einstellen 2026: Der vollständige Leitfaden
Häufig gestellte Fragen (FAQ)
Welche Java-Version sollte ich für Spring Boot 2026 verwenden?
Java 21 (LTS) ist die empfohlene Version für Spring Boot 3.4 in 2026. Java 21 bietet Virtual Threads (Project Loom) für bessere Skalierung, Pattern Matching für prägnantere Switch-Ausdrücke, Record Patterns und Sequenced Collections. Spring Boot 3.4 setzt mindestens Java 17 voraus, aber Java 21 ist der Standard für neue Projekte. Wenn Sie GraalVM Native Image nutzen wollen, ist Java 21 ebenfalls die beste Wahl.
Was ist der Unterschied zwischen Spring Boot und Spring Framework?
Das Spring Framework ist das Basis-Framework mit Dependency Injection, AOP (Aspect-Oriented Programming) und Kernmodulen wie Spring MVC, Spring Data und Spring Security. Spring Boot ist eine Erweiterung, die Auto-Configuration, eingebettete Server (Tomcat, Jetty, Undertow), Starter-Dependencies und Production-Ready-Features (Actuator für Health Checks, Metriken) hinzufügt. In der Praxis: Mit Spring Boot erstellen Sie in Minuten eine lauffähige Anwendung, die Konfiguration erfolgt über application.yml statt über XML-Dateien. Über 95% der neuen Spring-Projekte nutzen Spring Boot.
Soll ich Maven oder Gradle für Spring Boot verwenden?
Beide Build-Tools sind vollständig unterstützt. Maven ist in deutschen Unternehmen und Enterprise-Projekten weiter verbreitet — über 65% der Spring-Boot-Projekte in DACH nutzen Maven. Gradle bietet schnellere Builds durch inkrementelle Kompilierung und Build-Cache und ist bei Android- und Kotlin-Projekten Standard. Für Einsteiger empfehle ich Maven wegen der besseren Dokumentation und der breiteren Community-Unterstützung im deutschsprachigen Raum. Für große Monorepos oder Performance-kritische CI/CD-Pipelines kann Gradle 20–40% Build-Zeit sparen.
Wie viel verdient ein Java/Spring-Boot-Entwickler in Deutschland 2026?
Junior Java/Spring-Boot-Entwickler verdienen 2026 zwischen 45.000 und 58.000 Euro brutto pro Jahr. Mid-Level mit 3–5 Jahren Erfahrung liegen bei 58.000 bis 78.000 Euro. Senior-Entwickler mit 5+ Jahren Spring-Boot-Erfahrung, Microservices und Cloud-Kenntnissen verdienen 78.000 bis 105.000 Euro. In München und Frankfurt liegen die Gehälter 10–15% über dem Bundesdurchschnitt. Für Freelancer liegt der Tagessatz bei 600–950 Euro netto. Spring-Boot-Entwickler mit zusätzlicher Kubernetes- oder KI-Erfahrung können bis zu 15% Gehaltszuschlag erwarten.
Java-Entwickler für Ihr nächstes Projekt?
Von Junior bis Staff — wir vermitteln erfahrene Java/Spring-Boot-Entwickler an deutsche Unternehmen. 21-Tage-Pipeline, 500+ vorgeprüfte Profile, Equity-Beratung inklusive.
Jetzt Beratungstermin buchen →Geschrieben von Anna Schneider, Backend-Entwicklerin mit 8 Jahren Spring-Boot-Erfahrung in Enterprise-Projekten bei SAP, Deutsche Bank und mehreren Berliner Startups. Letztes Update: 7. Juni 2026.