Java EE ist tot - es lebe Spring (Boot)!

Freitag, 13.9.2019

JAVA-EE-Header-Blog-Serie_viadee

Der Java-EE-Standard liegt auf dem Sterbebett und das Spring-Ökosystem hat die Vorreiterrolle als Quasi-Standard im Enterprise-Java-Umfeld übernommen. Die Übergabe des Java-EE-Standards von Oracle an die Eclipse Foundation und der neue Name Jakarta EE sind eher der letzte Sargnagel als ein Neubeginn. Warum ist das so?
In unserer Blog-Serie "Sprungbrett: Das Leben nach Java EE" werden unterschiedliche Aspekte beleuchtet und anstehende Architektur-Entscheidungen begleitet. 

Neben der höheren Geschwindigkeit bei Neuerungen, die das Spring-Ökosystem gegenüber dem trägen Standardisierungsprozess von Java EE auszeichnet, scheint sich Java nur aus der Spring-Community heraus für die Anforderungen der Cloud wappnen zu können. In einer Microservice-Umgebung ist kein Platz für schwergewichtige Application Server. Vielmehr setzen Container-Technologien wie Docker und Kubernetes die Maßstäbe. Darüber hinaus bieten diese im Gegensatz zu Application Servern auch eine Laufzeitumgebung für Anwendungen, die nicht in Java geschrieben sind, sondern auf Node.js oder Python setzen.

Adam Wiggins, der Mitbegründer von Heroku, hat mit The Twelve-Factor App bereits 2011 die Prinzipien für die Implementierung und das Deployment von Webanwendungen oder Software-as-a-Service beschrieben, die

  • deklarative Formate benutzen für die Automatisierung der Konfiguration, um Zeit und Kosten für neue Entwickler im Projekt zu minimieren;
  • einen sauberen Vertrag mit dem zugrundeliegenden Betriebssystem haben, maximale Portierbarkeit zwischen Ausführungsumgebungen bieten;
  • sich für das Deployment auf modernen Cloud-Plattformen eignen, die Notwendigkeit von Servern und Serveradministration vermeiden;
  • die Abweichung minimieren zwischen Entwicklung und Produktion, um Continuous Deployment für maximale Agilität zu ermöglichen;
  • und skalieren können ohne wesentliche Änderungen im Tooling, in der Architektur oder in den Entwicklungsverfahren (zitiert aus der deutschen Übersetzung https://12factor.net/de/)

In diesem Blogpost werde ich, ausgehend von der These, dass eine cloudfähige Webanwendung implementiert werden soll, anhand dieser zwölf Faktoren bewerten, ob Java EE eine geeignete Lösung ist, und als Vergleich Spring (Boot) heranziehen.

JavasEE-vs-Spring-Boot
Java EE - monolithisch aber rock-solid? Wenn ja - wie lange noch?

Nicht alle der zwölf Faktoren sind anwendbar auf den Java-EE-Standard. Die Versionsverwaltung (Codebase), die Trennung der Build-Phase von der Run-Phase, die Behandlung von Logs als Ereignisstrom und die Ausführung von Admin-/Management-Aufgaben sind unabhängig von Java EE und werden daher nicht betrachtet.

Abhängigkeiten explizit deklarieren

"Eine Zwölf-Faktor-App verlässt sich nie auf die Existenz von systemweiten Paketen" (https://12factor.net/de/dependencies) ist ein Prinzip, das dem Application-Server-Ansatz bewusst widerspricht. In Java EE verlässt man sich darauf, dass für die benutzten APIs eine Implementierung durch den Application Server bereitgestellt wird. In Maven gibt es dafür sogar den Scope provided für Abhängigkeiten, die vom Servlet Container bereitgestellt werden.

Spring Boot in Reinkultur hingegen erfüllt dieses Prinzip und erzeugt in sich abgeschlossene Anwendungen mit allen Abhängigkeiten, in denen der Servlet Container bewusst integriert ist. Spring-Boot-Anwendungen werden dann nicht als war-Datei auf einem Application Server deployed, sondern direkt als jar-Datei gestartet. Das hat einerseits Vorteile für die einfachere Entwicklung, da keine Infrastruktur auf der Entwicklungsmaschine benötigt wird. Andererseits werden auch der Betrieb und die Skalierung vereinfacht, da auch Test- und Produktivsysteme ohne weitere Abhängigkeiten auskommen. Langfristig erhöht dieses Vorgehen auch die Wartbarkeit, da Migrationsprojekte von einem Application Server zum anderen beim Hersteller- oder Versionswechsel der Vergangenheit angehören. Falls die Anwendung einen neuen Servlet Container braucht, kann man diesen einfach in den neuen Deployments austauschen und ältere Deployments nach und nach ersetzen.

Konfiguration in Umgebungsvariablen speichern

Die betriebliche Konfiguration, die insbesondere für das Deployment wichtig ist, darf kein Teil der Codebasis im Repository sein. Das gilt für Ressourcendefinitionen (z. B. Datenbank-Verbindungen), Credentials für den Zugriff auf andere Anwendungen oder externe Dienste und auch für andere Parameter, die abhängig vom Deployment sind, wie z. B. Hostnamen. Die Zwölf-Faktor-Prinzipien sehen vor, dass die Deployment-Konfiguration vollständig über Umgebungsvariablen gesteuert wird. Ausnahmen hiervon sind die Anwendungskonfiguration, z. B. die Spring-Konfiguration oder JPA-Konfigurationen für das Datenbank-Mapping.

Im Java-Ökosystem haben sich für die Anwendungskonfiguration Annotationen direkt an den jeweiligen POJO-Klassen etabliert, die von diesem Prinzip auch nicht berührt werden. Betriebliche Konfigurationsparameter sind häufig in Properties-Dateien abgelegt, die dann im Build/Deployment als Parameter herangezogen werden. Grundsätzlich sind dabei Umgebungsvariablen integrierbar, sodass dieses Prinzip sowohl mit Java EE als auch im Spring-Umfeld umsetzbar ist. Allerdings existieren sicherlich viele Java-EE-Anwendungen, die dieses Prinzip verletzen und deswegen nicht ohne weiteres Cloud-fähig sind. Bei Spring Boot hingegen kann man mit der PropertySource jeden Key aus einer Properties-Datei als Umgebungsvariable übergeben, welche bevorzugt verwendet werden.

Unterstützungsdienste als angehängte Ressourcen behandeln

Alle Dienste, die eine Anwendung zur Erfüllung der Funktionalität benötigt, seien es Datenbanken, Messaging-Systeme oder von Dritten oder in der Cloud bereitgestellte Dienste wie die Twitter- oder Google-Maps-API, sollen gemäß diesem Prinzip gleich behandelt werden. Alle Dienste werden über eine URL als Ressource aufgerufen und die Parameter für den Zugriff in der Deployment-Konfiguration verwaltet. Damit wird erreicht, dass die Anwendung nicht abhängig von lokalen Diensten ist. Für die Anwendung ist es transparent, ob der Dienst im eigenen Rechenzentrum, einer privaten oder hybriden Cloud oder im offenen Internet bereitgestellt wird, da der Zugriff immer über eine URL erfolgt. Damit wird eine lose Kopplung zwischen der Anwendung und den benötigten Diensten erreicht, die den Austausch von Ressourcen im Deployment ohne Code-Änderungen ermöglicht. Diese Eigenschaft lässt sich sowohl mit Java EE als auch mit Spring erfüllen.

Anwendungen als zustandslose Prozesse ausführen

Zwölf-Faktor-Anwendungen sollen zustandslos sein und dem Shared-Nothing-Ansatz folgen. Daraus leitet sich ab, dass jede Anfrage an einen beliebigen Systemprozess bzw. eine beliebige Instanz geroutet werden kann und alle Daten zur Erfüllung der Anfrage in Unterstützungsdiensten gespeichert sind. Das heißt, es gibt keine Session-Daten im Arbeitsspeicher des Anwendungsprozesses und auch keine Sticky Sessions, bei denen alle Anfragen desselben Benutzers zur selben Instanz geroutet werden. Statt des Arbeitsspeichers können Caching-Lösungen wie Memcached oder Redis als Unterstützungsdienste verwendet werden.

Die Servlet-API als Teil von Java EE setzt auf eine zustandsbehaftete HttpSession, die diesem Prinzip widerspricht. Im Spring-Ökosystem gibt es mehrere Möglichkeiten zur Realisierung von Web-Anwendungen wie Spring MVC oder Spring Web Flow, die ebenfalls teilweise auf eine zustandsbehaftete Session setzen. Eine häufig gewählte Architektur setzt stattdessen auf Spring-basierte, zustandslose REST-Services im Backend und eine Single Page App mit modernen JavaScript-Frameworks im Frontend. In diesem Fall hängt es also vom konkreten Einsatzszenario ab, aber die Erfüllung des Prinzips ist mit einer Spring-basierten Architektur möglich.

Dienste durch das Binden eines Ports exportieren

Auch wenn dieses Prinzip etwas sperrig formuliert ist, bedeutet es letztlich, dass die Anwendung vollständig eigenständig ist und keinen externen Webserver oder Application Server zur Laufzeit benötigt - der exakte Gegenentwurf zum Java-EE-Ansatz. Mit Spring Boot wird dieses Prinzip dadurch erreicht, dass ein eingebetteter Servlet Container wie Jetty oder Tomcat als explizite Abhängigkeit mit ausgeliefert wird und damit eine unabhängige Laufzeitumgebung vollständig bereitsteht.

Durch unabhängige Prozesse skalieren

Zwölf-Faktor-Anwendungen setzen auf eine horizontale Skalierung durch viele parallele Prozesse bzw. Instanzen, die isoliert voneinander laufen. Diese Form der elastischen Skalierung ist eine zentrale Eigenschaft der Cloud. Die Nebenläufigkeit und Parallelisierung von Anwendungen wird damit wesentlich vereinfacht und eine schnelle Reaktion auf Lastspitzen oder unerwarteten Erfolg der Webanwendung ist möglich. Mit Spring Boot kann diese Art der Skalierung umgesetzt werden, sofern wirklich zustandslose Prozesse damit implementiert werden. Java EE hingegen verfolgt den Ansatz einer vertikalen Skalierung, indem der Application Server und die darin laufende Java Virtual Machine (JVM) mit mehr Systemressourcen ausgestattet werden oder leistungsfähigere Hardware beschafft wird.

Robuster mit Wegwerfprozessen

Dieser Faktor verlangt, dass Prozesse jederzeit gestartet oder gestoppt werden können, ohne Auswirkungen auf die Benutzer der Anwendung zu verursachen. Dies erhöht die Robustheit des Gesamtsystems durch bessere Skalierbarkeit und schnellere Deployments. Eine Spring-Boot-Anwendung kann als Wegwerfprozess ausgeführt werden. Allerdings handelt es sich dabei um eher schwergewichtige Prozesse durch die JVM und den eingebetteten Servlet Container mit entsprechend langen Startup-Zeiten. Um die angestrebte minimale Anlaufzeit zu erreichen, gibt es mittlerweile mehrere Technologien wie Quarkus, Micronaut und GraalVM.

Im Java-EE-Umfeld sind der Application Server und die darin deployten Webanwendungen auf einen Endlosbetrieb ausgelegt und es ist nur schwer vorstellbar, daraus Wegwerfprozesse zu designen.

Entwicklung und Produktion ähnlich halten

Zur Unterstützung von Continuous Deployment und um DevOps zu ermöglichen, sollten Entwicklungs- und Produktionsumgebung so ähnlich wie möglich sein - idealerweise komplett identisch bis auf andere Ressourcen-URLs und eine größere Anzahl von Prozessen bzw. Deployments in Produktion. Damit gehören auch merkwürdige Effekte und Diskussionen wie das berühmt-berüchtigte „auf meinem Entwicklungsrechner läuft es - in Produktion aber nicht“ der Vergangenheit an.

Spring Boot ist ein idealer Kandidat zur Umsetzung dieses Prinzips, wenn man die Spring-Boot-Anwendung als Docker-Container verpackt und dort die JVM mitliefert - ansonsten besteht noch eine Abhängigkeit zur lokal installierten JVM, die zwischen Entwicklung und Produktion abweichen kann. Für Java EE lässt es sich hingegen nur schwer umsetzen, da der schwergewichtige Application Server allein aus Lizenz-, Performance- und Komplexitätsgründen nicht auf jedem Entwicklerrechner laufen kann. Für die üblicherweise genutzten Ressourcen wie relationale Datenbanken oder Message-Queue-Systeme gilt das genauso. Der Betrieb dieser Systeme hat in der Vergangenheit häufig eine „Wissenschaft für sich“ dargestellt und auf diese Expertise hat sich der IT-Betrieb spezialisiert, sodass Entwickler auf ihren lokalen Systemen auf vereinfachte Technologien wie H2 als Datenbank ausgewichen sind.

Zusammenfassung: Java EE ist Legacy

Nach der Betrachtung der einzelnen Faktoren fasst die Tabelle nochmal die vereinfachte Einschätzung der Erfüllung der Faktoren durch das Spring-Ökosystem mit Spring Boot und durch den Java-EE-Standard zusammen.


Faktor Spring (Boot) Java EE
 Abhängigkeiten explizit deklarieren ✔️
 Konfiguration in Umgebungsvariablen speichern ✔️ ✔️
 Unterstützungsdienste als angehängte Ressourcen behandeln ✔️ ✔️
 Anwendungen als zustandslose Prozesse ausführen ✔️
 Dienste durch das Binden eines Ports exportieren ✔️
 Durch unabhängige Prozesse skalieren ✔️
 Robuster mit Wegwerfprozessen ✔️
 Entwicklung und Produktion ähnlich halten ✔️


Natürlich bestehen nicht für jede Unternehmensanwendung alle Anforderungen, die sich aus den Zwölf-Faktor-Prinzipien ableiten. Gleichwohl gibt es durch die DevOps-Bewegung und den vermehrten Einsatz von Container-/Cloud-Technologien einen deutlichen Trend in diese Richtung. Es lohnt sich also, zu hinterfragen, ob Java EE noch die richtige Entscheidung für eine zukunftsfähige IT-Architektur ist. Meine Einschätzung spiegelt sich in der Tabelle in einem deutlichen NEIN wider. Das bedeutet nicht, dass jede Java-EE-Anwendung von heute auf morgen abgeschaltet werden muss, aber zumindest, dass Java EE für neue Anwendungen nicht mehr die primäre Technologie sein sollte. Damit muss man konsequenterweise Java EE als Legacy-Technologie betrachten, die mittelfristig abgelöst werden sollte.

Die Antwort auf die Frage „Was nutzen wir stattdessen?“ liefert dieser Blogpost implizit gleich mit: Das Spring-Ökosystem mit Spring Boot als Laufzeitumgebung erfüllt die Zwölf-Faktor-Prinzipien und ermöglicht gleichzeitig die Integration oder Übernahme von bestehender Java-Geschäftslogik. Die konkreten Herausforderungen bei der Migration von Java EE auf Spring Boot werden wir in mehreren weiteren Blogposts im Detail beleuchten. Für alle, die noch tiefer eintauchen wollen, bieten wir eine Schulung für Spring Core und Spring Boot an.
Jetzt informieren und Kontakt aufnehmen



Ich möchte meinem Kollegen Sebastian Sirch (einem unserer Cloud-Experten) für den Hinweis auf die Zwölf-Faktor-Prinzipien und andere wertvolle Tipps danken, ohne die dieser Blogpost nie entstanden wäre.


 

DIESER BEITRAG IST TEIL EINER SERIE:
Teil 1: Java EE ist tot – es lebe Spring (Boot)!
Teil 2: Im Griff der Würgefeige: Herausforderungen bei der Spring Migration
Teil 3: Mein JEE-API im Application-Server ist weg. Was nun? 
Teil 4: Weg von Java EE - so gelingt die Migration

CTA - Anmeldung zur Blog-Serie - Das Leben nach JAVA EE


 


zurück zur Blogübersicht

Diese Beiträge könnten Sie ebenfalls interessieren

Keinen Beitrag verpassen – viadee Blog abonnieren

Jetzt Blog abonnieren!

Kommentare

Tobias Voß

Tobias Voß

Tobias Voß arbeitet als IT-Architekt in agilen Projekten bei der viadee. Er berät Kunden im Versicherungs- und Bankenumfeld bei der Umsetzung individueller Softwaresysteme mit den Schwerpunkten Java, Architektur und Prozessautomatisierung und leitet den Kompetenzbereich Java & Architektur der viadee.

Tobias Voß bei Xing  Tobias Voß auf Twitter