Spring Boot ist das populärste Java-Framework für Webanwendungen. Es erstellt ausführbare JAR-Dateien mit eingebettetem Tomcat-Server, die einfach zu deployen sind.
Java installieren
OpenJDK
# Debian/Ubuntu
apt install openjdk-21-jdk
# CentOS/RHEL
dnf install java-21-openjdk-devel
# Version prüfen
java -versionJAVA_HOME setzen
echo 'export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64' >> /etc/profile.d/java.sh
echo 'export PATH=$PATH:$JAVA_HOME/bin' >> /etc/profile.d/java.sh
source /etc/profile.d/java.shSpring Boot Projekt
Build-Tools
# Maven
apt install maven
# Oder Gradle
apt install gradleProjekt erstellen
# Spring Initializr
curl https://start.spring.io/starter.zip \
-d type=maven-project \
-d language=java \
-d bootVersion=3.2.0 \
-d baseDir=myapp \
-d groupId=de.example \
-d artifactId=myapp \
-d name=myapp \
-d dependencies=web,data-jpa,postgresql \
-o myapp.zip
unzip myapp.zip
cd myappEinfache REST-API
// src/main/java/de/example/myapp/MyappApplication.java
package de.example.myapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyappApplication {
public static void main(String[] args) {
SpringApplication.run(MyappApplication.class, args);
}
}// src/main/java/de/example/myapp/controller/ApiController.java
package de.example.myapp.controller;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/health")
public Map<String, String> health() {
return Map.of("status", "healthy");
}
@GetMapping("/users")
public List<User> getUsers() {
return userService.findAll();
}
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.save(user);
}
}application.properties
# src/main/resources/application.properties
# Server
server.port=8080
server.servlet.context-path=/
# Datenbank
spring.datasource.url=jdbc:postgresql://localhost:5432/myapp
spring.datasource.username=${DB_USER:myapp}
spring.datasource.password=${DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=validate
# Logging
logging.level.root=INFO
logging.level.de.example=DEBUG
logging.file.name=/var/log/myapp/application.log
# Actuator (Monitoring)
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=alwaysapplication-production.properties
# src/main/resources/application-production.properties
spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:5432/${DB_NAME:myapp}
spring.datasource.hikari.maximum-pool-size=20
spring.jpa.show-sql=false
# Compression
server.compression.enabled=true
server.compression.mime-types=application/json,text/html,text/plain
# SSL (optional, wenn nicht Nginx)
# server.ssl.key-store=classpath:keystore.p12
# server.ssl.key-store-password=${KEYSTORE_PASSWORD}JAR erstellen
Mit Maven
./mvnw clean package -DskipTests
# Ergebnis: target/myapp-0.0.1-SNAPSHOT.jarMit Gradle
./gradlew bootJar
# Ergebnis: build/libs/myapp-0.0.1-SNAPSHOT.jarAusführbare JAR
# Test
java -jar target/myapp-0.0.1-SNAPSHOT.jar
# Mit Profil
java -jar -Dspring.profiles.active=production target/myapp-0.0.1-SNAPSHOT.jarDeployment
Verzeichnisstruktur
mkdir -p /var/www/myapp
mkdir -p /var/log/myapp
mkdir -p /etc/myapp
# JAR kopieren
cp target/myapp-0.0.1-SNAPSHOT.jar /var/www/myapp/myapp.jar
# Berechtigungen
chown -R www-data:www-data /var/www/myapp
chown -R www-data:www-data /var/log/myappKonfigurationsdatei
# /etc/myapp/application.properties
spring.profiles.active=production
server.port=8080
# Datenbank
spring.datasource.url=jdbc:postgresql://localhost:5432/myapp
spring.datasource.username=myapp
spring.datasource.password=sicheres_passwort
# Logging
logging.file.name=/var/log/myapp/application.logSystemd-Service
myapp.service
# /etc/systemd/system/myapp.service
[Unit]
Description=My Spring Boot Application
After=network.target postgresql.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
Environment="JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64"
Environment="SPRING_CONFIG_LOCATION=/etc/myapp/"
ExecStart=/usr/bin/java \
-Xms256m \
-Xmx512m \
-XX:+UseG1GC \
-jar /var/www/myapp/myapp.jar
ExecStop=/bin/kill -15 $MAINPID
Restart=on-failure
RestartSec=10
SuccessExitStatus=143
TimeoutStopSec=30
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetJVM-Optionen
# Für größere Apps
ExecStart=/usr/bin/java \
-Xms512m \
-Xmx2g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/myapp/heapdump.hprof \
-Djava.security.egd=file:/dev/./urandom \
-jar /var/www/myapp/myapp.jarService starten
systemctl daemon-reload
systemctl enable myapp
systemctl start myapp
systemctl status myapp
# Logs
journalctl -u myapp -fNginx Reverse Proxy
# /etc/nginx/sites-available/myapp
upstream springboot {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
server_name api.example.de;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.example.de;
ssl_certificate /etc/letsencrypt/live/api.example.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.de/privkey.pem;
access_log /var/log/nginx/myapp-access.log;
error_log /var/log/nginx/myapp-error.log;
client_max_body_size 10M;
location / {
proxy_pass http://springboot;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
# Actuator nur intern
location /actuator {
allow 127.0.0.1;
deny all;
proxy_pass http://springboot;
}
}Monitoring mit Actuator
Dependencies
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>Endpoints
# Health Check
curl http://localhost:8080/actuator/health
# Metriken
curl http://localhost:8080/actuator/metrics
curl http://localhost:8080/actuator/metrics/jvm.memory.used
# Info
curl http://localhost:8080/actuator/infoPrometheus Integration
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>management.endpoints.web.exposure.include=prometheus,health
management.metrics.export.prometheus.enabled=trueZero-Downtime Deployment
Blue-Green Deployment
#!/bin/bash
# deploy.sh
APP_PATH="/var/www/myapp"
NEW_JAR="myapp-new.jar"
CURRENT_JAR="myapp.jar"
# Neue Version kopieren
cp target/myapp-*.jar $APP_PATH/$NEW_JAR
# Health Check der neuen Version
java -jar $APP_PATH/$NEW_JAR --server.port=8081 &
NEW_PID=$!
sleep 30
if curl -f http://localhost:8081/actuator/health; then
# Neue Version erfolgreich
kill $NEW_PID
# Austauschen
mv $APP_PATH/$CURRENT_JAR $APP_PATH/myapp-old.jar
mv $APP_PATH/$NEW_JAR $APP_PATH/$CURRENT_JAR
systemctl restart myapp
echo "Deployment erfolgreich"
else
# Fehler
kill $NEW_PID
rm $APP_PATH/$NEW_JAR
echo "Deployment fehlgeschlagen"
exit 1
fiDatenbank-Migration mit Flyway
Dependency
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>Migrations
-- src/main/resources/db/migration/V1__Create_users_table.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);# application.properties
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migrationZusammenfassung
| Komponente | Funktion | |------------|----------| | Spring Boot | Framework | | Embedded Tomcat | Application Server | | Nginx | Reverse Proxy | | Actuator | Monitoring | | Flyway | DB-Migration |
| Befehl | Funktion | |--------|----------| | mvn package | JAR erstellen | | java -jar | Anwendung starten | | systemctl | Service-Management |
| JVM-Option | Funktion | |------------|----------| | -Xms | Minimaler Heap | | -Xmx | Maximaler Heap | | -XX:+UseG1GC | G1 Garbage Collector |
| Datei | Funktion | |-------|----------| | /var/www/myapp/myapp.jar | Anwendung | | /etc/myapp/application.properties | Konfiguration | | /var/log/myapp/ | Logs |
Fazit
Spring Boot vereinfacht das Java-Deployment erheblich. Ausführbare JARs mit eingebettetem Server sind einfach zu handhaben. Actuator bietet umfassendes Monitoring out-of-the-box. Mit Flyway lassen sich Datenbank-Migrationen automatisieren. Für Enterprise-Anwendungen bleibt Spring Boot die erste Wahl im Java-Ökosystem.