Von Thomas Rohde auf Montag, 08. Dezember 2025
Kategorie: Application Development

Systemintegration einfach wie nie: Spring Boot-Applikation als Service unter Linux einrichten und betreiben

Spring Boot ist ein Framework für effektive Software-Entwicklung und besonders beliebt für den Einsatz im Backend. Seit vielen Jahren ist es fester Bestandteil der Enterprise-Entwicklung mit Java. Für die Ausführung in Containern und als Wegbereiter für Java in Cloud-Infrastrukturen konzipiert, können solche Applikationen aber auch eher klassisch und sehr einfach auf Linux-Systemen betrieben werden.

Dieser Artikel zeigt, wie man:

java -jar war gestern

Wenn man sich mit Spring Boot beschäftigt, stößt man schnell auf das Spring-Boot-Maven-Plugin, welches in jeder Spring Boot-Anwendung in der pom.xml definiert ist. Erstellt man ein Basis-Projekt auf https://start.spring.io, wird es im Abschnitt build mit einem sehr minimalistischen Eintrag in der pom.xml generiert (s. Listing 1). 

Listing 1: Das Spring Boot Maven Plugin 

Dadurch wird es im Maven-Build-Prozess in der Lifecycle-Phase package ausgeführt und sorgt zunächst dafür, dass die zuvor vom Maven-Jar-Plugin erzeugte Jar-Datei umbenannt wird. Aus hello-prod.jar wird bspw. hello-prod.jar.original. Anschließend erzeugt das Spring-Boot-Maven-Plugin eine neue Jar-Datei. Dieses ist ein sog. Uber- oder Fat-Jar. Es enthält neben den eigenen Class-Files auch noch sämtliche verwendete Bibliotheken (Libs) und einen eigenen Class-Loading- und Bootstrapping-Mechanismus von Spring Boot, damit die Jar-Datei als eigenständige Java-Anwendung gestartet werden kann. Das erfolgt üblicherweise mit dem Befehl java -jar hello-prod.jar.

Einen solchen Befehl kann man jetzt relativ einfach in ein Dockerfile übernehmen, und der Weg für die Laufzeitumgebung innerhalb eines Docker-Containers ist geebnet. In eher klassischen Infrastrukturen, wie einem Deployment auf einer Linux-VM würde ein:e Systemintegrator:in jetzt wahrscheinlich zur Allzweckwaffe Shell-Skript greifen und für init.d oder Systemd ein entsprechendes Wrapper-Skript mit den Funktionen start, stop, restart etc. erstellen oder aus dem Ärmel zaubern.

Wie so häufig haben die Spring Boot-Entwickler:innen auch hier schon mitgedacht und haben so etwas bereits in das Spring-Boot-Maven-Plugin integriert. Mit dem Parameter executable (s. Listing 2) wird aus einer Jar-Datei ein ausführbares Binary. 

Listing 2: Das Spring Boot Maven Plugin mit dem Parameter executable

Was jetzt passiert ist zwar ein bisschen pragmatisch und etwas dirty, führt aber oft zum gewünschten Ergebnis. Das Plugin erstellt weiterhin ein Fat-Jar mit allen notwendigen Ressourcen. An den Anfang der Datei wird aber noch ein universelles Shell-Skript angefügt. Damit entsteht eine einzige Datei, die sowohl als Shell-Skript, aber auch als Java-Binary fungiert. Schaut man sich die Datei mit einem Texteditor (z. B. less) an, findet man ungefähr in den ersten 300 Zeilen Shell-Code vor. Danach geht es binär mit dem Inhalt des eigentlichen Jar-Files weiter.

Jetzt lässt sich ein solches Executable in der Bash einfach mit ./hello-prod.jar starten. Das Shell-Skript enthält die Logik zur Erkennung, ob es als Service ausgeführt wird, dann werden die Parameter start, stop, restart, status, force-stop und force-reload unterstützt. Wird es nicht als Service gestartet, wird der Default-Parameter run gesetzt.

Spring Boot als Service einrichten

Mit dem erstellten Executable kann man jetzt den nächsten Schritt in Angriff nehmen und auf einem Linux-System einen Service einrichten. Für dieses Beispiel wird ein Ubuntu 22.04 LTS verwendet. Bei anderen Distributionen funktioniert es ähnlich.

Zunächst muss für Systemd eine Service-Datei mit dem in Listing 3 definierten Inhalt angelegt werden. 

Listing 3: Die Systemd-Konfiguration für die Spring Boot-Anwendung

Wie man hier sehen kann, wird als Startprogramm lediglich der Dateipfad zur Jar-Datei hello-prod.jar angegeben.

Ein Blick in das Verzeichnis /opt/hello-service (s. Listing 4) offenbart ein paar weitere Besonderheiten. 

Listing 4: Der Inhalt des Verzeichnisses /opt/hello-service

Die im Service definierte Jar-Datei ist tatsächlich ein symbolischer Link auf eine Jar-Datei mit der Versionsnummer im Namen. Das muss man nicht so machen, hilft aber vielleicht beim Umgang mit verschiedenen Artefakten und bei Continuous Deployment.

Die Datei application-prod.properties wird von Spring Boot automatisch eingelesen und für das Überschreiben gewisser Properties beim Start mit dem Profil prod verwendet. Hier kann man umgebungspezifische und kritische Informationen ablegen, die man besser nicht im Quellcode-Repository verwalten möchte, wie z. B. Credentials für eine Datenbankverbindung.

Im Verzeichnis logs werden Log-Dateien abgelegt, doch dazu später mehr.

Werfen wir zunächst im nächsten Kapitel einen Blick auf die Datei hello-prod.conf. 

Programmargumente und JVM-Parameter definieren

Wenn man eine Java-Anwendung klassisch mit dem Befehl java -jar aufruft, kann man sowohl JVM-Parameter als auch Programmargumente übergeben:

java -XX:+PrintFlagsFinal -Xmx512m -jar target/hello-prod.jar \
--spring.profiles.active=prod

Registriert man eine Java-Anwendung als Systemd-Service entfällt die direkte Möglichkeit dafür. Allerdings kann man eine spezielle Datei mit der Endung .conf neben das Jar legen und diese wird dann vom o. g. Spring Boot-Shell-Skript eingelesen. Darin lassen sich einfach Umgebungsvariablen definieren, welche dann für den Ausführungskontext des Services geladen werden.

In unserem Beispiel sehen wir in Listing 5 den Inhalt der Datei hello-prod.conf. 

Listing 5: Der Inhalt der Datei hello-prod.conf

Mit der Variable RUN_ARGS können Programmargumente definiert werden, die an die Spring Boot-Anwendung übergeben werden. Diese landen im String-Array args der statischen Methode main der Application-Klasse.

Die Variable JAVA_OPTS definiert Optionen, die an die JVM übergeben werden. Oft wird dies für Speicher-Parameter oder GC-Tunings verwendet.

Über die Variable PID_FOLDER kann man den Speicherort des PID-Files angeben. Standardmäßig ist dies /var/run.

Eine vollständige Liste der unterstützten Umgebungsvariablen findet man in der Spring Boot-Dokumentation [1]. 

Logging – ein Klassiker

Klassische Java-Anwendungen schreiben Ereignisse üblicherweise in Log-Dateien. Normalerweise schreibt Spring Boot seine Ausgaben auf die Standardausgabe (stdout). Aber natürlich wird im Java-Quellcode von Spring eine Logging-API [2] verwendet und nicht einfach mit System.out.println(...) gearbeitet. Dieses Vorgehen empfiehlt sich auch für den eigenen Code, z. B. mithilfe von SLF4J [3]. Dann ist es auch relativ einfach, die Ausgaben in Log-Dateien umzuleiten. Spring Boot nutzt als Logging-Bibliothek Logback [4].

Es gibt verschiedene Möglichkeiten, Einfluss auf das Logging-Verhalten einer Spring Boot-Anwendung zu nehmen. Viele Parameter lassen sich bereits über die application.properties definieren. Komplexere Anpassungen können in einer eigenen Datei (z. B. logback-spring.xml) vorgenommen werden. In unserem Fall reichen die Möglichkeiten in der application.properties vollkommen aus. Listing 6 zeigt ein Beispiel für eine Datei-basierte Logging-Konfiguration in der application-prod.properties: 

Listing 6: Logging-Konfiguration in der application-prod.properties

Durch die Leer-Zuweisung der Property logging.pattern.console werden keine Ausgaben mehr auf die Console geschrieben. Die Property logging.file.name definiert Pfad und Dateiname der entsprechenden Log-Datei. Damit werden die Ausgaben automatisch in diese Datei geschrieben.

Sehr praktisch für produktive Zwecke ist das automatische Housekeeping von Logback. Dieses kann über die Property-Gruppe logging.logback.rollingpolicy definiert werden. Mit max-file-size kann die maximale Dateigröße angeben werden und mit max-history kann man definieren, wie viele alte Dateien aufbewahrt werden sollen. Alte Dateien werden automatisch gelöscht. Hat die Log-Datei die definierte Dateigröße erreicht, wird diese umbenannt und in Form einer gz-Datei komprimiert. 

Access-Logs für Web-Applikationen und WebServices

In klassischen Web- oder Application-Servern ist die Verwendung von Access-Logs ein oft genutztes Feature, um ein standardisiertes Audit zu den eingehen HTTP-Anfragen zu erhalten. Dazu wird für jeden Request eine Log-Zeile in einer separaten Access-Log-Datei geschrieben. Eine solche Zeile enthält normalerweise einige Informationen über die Aufrufenden (z. B. IP-Adresse), eingehende HTTP-Request-Header, die URL und Informationen über die Antwort (z. B. Status-Code, Größe des Payloads). Listing 7 zeigt exemplarisch eine solche Zeile.  

Listing 7: Eintrag aus einem Access-Log

In dem Listing sieht man die IP-Adresse der/des Aufrufenden, einen Zeitstempel, die HTTP-Methode, URI, Protokoll-Version, Status-Code, Payload-Größe und die Information zum Browser (User-Agent).

In einem klassischen Tomcat-Server wird für das Erzeugen eines Access-Logs beispielsweise ein AccessLogValve [5] konfiguriert. Der Embedded-Tomcat in Spring unterstützt dieses Feature ebenfalls. Hierzu müssen nur wieder wenige Properties definiert werden (s. Listing 8). 

Listing 8: Konfiguration des Access-Logs in der application-prod.properties

Zunächst wird das Access-Log aktiviert. Dann definiert man den Pfad zum Verzeichnis, in dem die Log-Dateien abgelegt werden sollen. Zusätzlich kann mit server.tomcat.accesslog.pattern angegeben werden, wie eine Log-Zeile aufgebaut sein soll, bzw. welche Informationen enthalten sein sollen. Es gibt zwei standardisierte Patterns: common und combined. Alternativ kann der Aufbau auch selbst definiert werden. Listing 9 zeigt dies exemplarisch.  

Listing 9: Ein eigenes Format für das Access-Log

Der Platzhalter %t steht für den Zeitstempel, %a definiert die IP-Adresse der/des Aufrufenden, %r ist die erste Zeile aus dem Request, %s der Status-Code aus der Response, %D die Zeit, die für die Verarbeitung des Requests aufgewendet wurde. Eine vollständige Auflistung der möglichen Pattern-Attribute findet man in der Tomcat-Dokumentation [5].

Bei Verwendung von Undertow oder Jetty als embedded Web-Server funktioniert die Konfiguration ähnlich. Details hierzu findet man in der Spring Boot-Dokumentation [6]. 

Fazit und Ausblick

In diesem Artikel wurde aufgezeigt wie sich eine Spring Boot-Applikation auf klassischen Linux-Servern einrichten und für den produktiven Einsatz konfigurieren lässt. Die Einrichtung als Service, die Möglichkeiten der externen Konfiguration und ein dateibasiertes Logging sind dabei nur ein paar wenige Beispiele.

Auch für die Laufzeitüberwachung bringt Spring Boot die notwendigen Monitoring-Endpunkte mit. Diese stellen auf Basis der Actuators [7] ein weiteres wichtiges Instrument für einen stabilen Betrieb dar. 

Quellen

Seminarempfehlungen

Verwandte Beiträge

Kommentare hinterlassen