arrow_backZurück zum Blog
DE
Architekturbeitrag

Java EE 11 ohne Nostalgie

Warum ich den Jakarta-Stack nicht aus Gewohnheit, sondern aus architektonischer Nüchternheit verwende

account_circleAnjunar09. September 2026Veröffentlicht

Der Titel dieses Artikels ist absichtlich leicht ungenau. Eigentlich müsste er natürlich „Jakarta EE 11 ohne Nostalgie“ heißen. Aber viele meinen mit „Java EE“ immer noch genau diese Welt: Standards, Container, CDI, JPA, Bean Validation, JAX-RS. Und genau darüber möchte ich sprechen.

Ich benutze diesen Stack nicht, weil ich an alten Enterprise-Zeiten hänge. Ich benutze ihn, weil er für bestimmte Arten von Systemen immer noch ein sehr vernünftiger Ausgangspunkt ist. Nicht spektakulär. Nicht trendig. Aber tragfähig.

Das größte Missverständnis ist, dass Standards angeblich automatisch schwergewichtig seien. In Wirklichkeit ist oft das Gegenteil der Fall. Ein Standardstack nimmt einem keine Architektur ab. Aber er zwingt einen auch nicht in eine große Produktphilosophie hinein. Er liefert Verträge, Lebenszyklen und bekannte Integrationspunkte. Den Rest muss man selbst sauber bauen. Genau das ist für mich ein Vorteil.

Ein Blick in dieses Projekt zeigt ziemlich gut, warum. Die Abhängigkeiten sind explizit. Nicht verborgen hinter einem Meta-Framework, das Build, Runtime, Reflection, HTTP, DI und Konfiguration zu einem einzigen großen Paket verschmilzt.

libraryDependencies ++= Seq(
  "jakarta.servlet" % "jakarta.servlet-api" % "6.1.0",
  "jakarta.authentication" % "jakarta.authentication-api" % "3.1.0",
  "jakarta.security.enterprise" % "jakarta.security.enterprise-api" % "4.0.0",
  "jakarta.ws.rs" % "jakarta.ws.rs-api" % "4.0.0",
  "jakarta.enterprise" % "jakarta.enterprise.cdi-api" % "4.1.0",
  "jakarta.transaction" % "jakarta.transaction-api" % "2.0.1",
  "org.jboss.resteasy" % "resteasy-core" % "7.0.2.Final",
  "org.jboss.resteasy" % "resteasy-cdi" % "7.0.2.Final",
  "org.jboss.resteasy" % "resteasy-undertow" % "7.0.2.Final"
)

Das ist für manche weniger bequem als ein großer Starter. Für mich ist es ehrlicher. Ich sehe, was wirklich Teil meiner Architektur ist. Ich weiß, worauf ich mich verlasse. Und wenn ich etwas austauschen will, muss ich nicht erst die implizite Logik eines Frameworks entwirren.

Dasselbe gilt für Konfiguration. Ich brauche keine gigantische Auto-Config-Maschine, wenn ich die wenigen Parameter, die mein System wirklich braucht, explizit lesen und als Modell ausdrücken kann.

ServerConfig(
  host = property("server.http.host", "localhost"),
  port = property("server.http.port", "8080").toInt,
  rootPath = property("server.http.root-path", "/service"),
  staticPath = staticPath,
  ssrEnabled = property("server.ssr.enabled", "true").toBoolean,
  ssrTimeoutMillis = property("server.ssr.timeoutMillis", "8000").toLong,
  datasourceUrl = property("datasource.jdbc.url", "jdbc:postgresql://localhost:5432/simplicityblog"),
  datasourceUsername = property("datasource.username", "postgres"),
  datasourcePassword = property("datasource.password", "postgres")
)

Was ich an diesem Stil mag: Er behandelt Infrastruktur als Infrastruktur. Nicht als Magie. Nicht als Bühne. Nicht als automatisches Wunder. Das System startet nicht deshalb gut, weil irgendwo im Hintergrund ein Framework tausend Entscheidungen für mich getroffen hat. Es startet gut, wenn die Entscheidungen verständlich und korrekt sind.

Gerade bei REST und Sicherheit finde ich das wichtig. JAX-RS, CDI und Security-Annotations sind keine perfekte Welt. Aber sie sind klar genug, um Verantwortung auszudrücken, ohne dabei den ganzen Anwendungscode unter einen Frameworkdialekt zu zwingen.

@GET
@Produces(Array("application/json"))
@RolesAllowed(Array("Anonymous", "Guest", "User", "Administrator"))
@EntityGraph("BlogPost.list")
def list(@BeanParam search: BlogPostSearch): Table[BlogPostsController.BlogPostRow] = {
  if (!currentIdentity.hasRole("Administrator")) {
    search.status = BlogPostStatus.PUBLISHED
  }
  ...
}

Das ist nicht aufregend. Genau deshalb ist es gut. Man sieht am Methodenkopf sofort, was diese Operation ist, wer sie aufrufen darf und unter welchem Entity-Graph sie läuft. Die interessanten Entscheidungen liegen im Code, nicht in einem verborgenen Startup-Prozess.

Viele moderne Stacks versprechen vor allem Geschwindigkeit beim Anfang. Das ist legitim. Mich interessiert aber stärker die Qualität in der Mitte und am Ende: Wie lesbar ist das System nach sechs Monaten? Wie austauschbar sind Teile? Wie gut kann man Fehler isolieren? Wie stark zieht das Framework das Modell an sich?

Bei Jakarta EE 11 mag ich, dass die Antwort oft überraschend unspektakulär ausfällt. Es gibt weniger Glamour. Aber auch weniger Theater. Wenn ich Dinge sauber aufbaue, dann trägt der Stack. Wenn ich Dinge schlecht aufbaue, rettet er mich nicht künstlich. Auch das ist für mich ein Vorzug.

Ich sehe darin also keine Rückkehr in eine vermeintlich goldene Vergangenheit. Ich sehe eine nüchterne Entscheidung für Standards, die nicht ständig Aufmerksamkeit verlangen. Das ist ein großer Unterschied.

Nostalgie will alte Sicherheit wiederholen. Architektur will heutige Probleme in tragfähiger Form lösen. Wenn ein Standardstack das besser unterstützt als eine lautere Alternative, dann ist die Entscheidung für mich nicht konservativ, sondern einfach vernünftig.

forum

Noch keine Kommentare.