Start / Seminare / Java SE in der Praxis
Modul
Richtung Produktion
5 Kapitel in diesem Modul-Video · Laufzeit
Transkript
Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.
Richtung Produktion
0:00 Funktional ist Kursradar fertig. Es holt Kurse, speichert sie und gibt sie über eine Schnittstelle wieder heraus. Trotzdem würde ich diese Anwendung so niemandem in die Hand drücken. Die Protokollausgabe ist uneinheitlich, wichtige Einstellungen stehen im Quelltext, und ohne Entwicklungsumgebung startet sie nicht. Genau diese Lücke zwischen läuft bei mir und läuft bei euch schließen wir in diesem Modul. Nichts davon ändert eine einzige Funktion.
0:26 Und trotzdem entscheidet es darüber, ob aus einem Projekt eine Anwendung wird, die jemand betreiben kann.
Richtung Produktion
0:32 Fünf Stationen. Zuerst bringen wir die Protokollausgabe auf ein einheitliches Format — das Problem haben wir im letzten Modul gesehen und vertagt. Dann holen wir die Konfiguration aus dem Code heraus. Danach räumen wir die Projektdateien auf, was seit dem dritten Modul überfällig ist. Und schließlich verpacken wir alles zu einer einzigen startbaren Datei.
0:53 Zum Schluss schauen wir nach vorn: Was können Sie mit diesem Bestand noch anfangen, und wie geht Ihr Weg als Java-Entwicklerin oder -Entwickler weiter? Vier Ziele, und sie haben eines gemeinsam: Es geht nicht mehr um Funktion, sondern um Betreibbarkeit. Protokollausgaben aus fremden Bibliotheken in ein einheitliches Format bringen, damit sie maschinell auswertbar sind. Werte herausnehmen, die sich je Umgebung ändern.
1:18 Versionen an einer Stelle pflegen statt in drei Dateien. Und die Anwendung so ausliefern, dass ein installiertes Java genügt. Das sind genau die Themen, die in Übungsprojekten fehlen — und die im ersten echten Projekt sofort auf den Tisch kommen.
Protokollierung vereinheitlichen
1:33 Erinnern Sie sich an den Serverstart aus dem letzten Modul? Da standen zwei völlig unterschiedliche Protokollformate untereinander. Ich hatte gesagt, dass das einen Grund hat und dass wir es später lösen. Später ist jetzt — und die Lösung ist erstaunlich elegant. Der Grund für die zwei Formate ist einfach: Unser Code protokolliert über die Fassade aus dem ersten Modul, Jersey dagegen über die Protokollierung, die im Java-Kern eingebaut ist.
2:00 Zwei Systeme, zwei Formate. Die Lösung ist eine Brückenbibliothek. Sie fängt die Aufrufe an die eingebaute Protokollierung ab und leitet sie an unsere Fassade weiter. Das Bild dazu: eine Weiche. Die alte Strecke bleibt liegen, es fährt nur nichts mehr darüber. Für die fremde Bibliothek ändert sich nichts — sie merkt gar nicht, dass ihre Meldungen woanders landen.
2:23 Der eigentliche Trick steckt weniger im Code als in seiner Position. Was Sie hier sehen, ist ein Block, der beim Laden der Klasse ausgeführt wird — noch bevor irgendeine Methode läuft. Das ist wichtig, denn die Umleitung muss stehen, bevor die erste Meldung geschrieben wird. Zwei Schritte passieren: Die eingebaute Protokollierung wird zurückgesetzt, damit sie nicht selbst noch etwas ausgibt, und danach wird die Weiche eingehängt.
2:48 Zwei Zeilen für ein Problem, das man sonst in jeder Ausgabe sieht. Merken Sie sich diesen Ort — Initialisierung, die früh passieren muss, gehört genau dorthin. Man könnte fragen, ob zwei Formate wirklich so schlimm sind. Solange Sie im Terminal mitlesen: nein. Der Unterschied entsteht im Betrieb. Protokolle werden dort eingesammelt, durchsucht und ausgewertet, und die Werkzeuge dafür zerlegen jede Zeile nach einem festen Muster.
3:13 Zwei Muster bedeuten, dass die Hälfte Ihrer Meldungen im Rauschen verschwindet — nicht sofort sichtbar, aber genau dann, wenn Sie sie brauchen. Dazu kommt ein zweiter Gewinn: Wenn Sie später die Protokoll-Umsetzung austauschen, gilt das für alle Ausgaben, auch für die aus fremden Bibliotheken. Der erste Punkt ist der häufigste: Die Bibliothek ist eingebunden, aber nirgends eingehängt — und dann passiert schlicht nichts.
3:38 Es gibt auch keine Fehlermeldung, denn technisch ist alles in Ordnung. Der zweite ist der Zeitpunkt: zu spät eingehängt, und die ersten Meldungen sind schon durch. Der dritte betrifft die Konstellation, zwei Umsetzungen gleichzeitig einzubinden — dann entscheidet der Zufall, welche gewinnt. Und der vierte ist eine Prüfempfehlung: Schauen Sie nicht auf Ihre eigenen Ausgaben, die waren nie das Problem. Schauen Sie auf die der fremden Bibliothek.
Konfiguration nach außen holen
4:04 Kommen wir zu einem Thema, das im Seminar oft belächelt und im Betrieb dann teuer wird. In unserem Code stehen an mehreren Stellen Werte fest verdrahtet — der Name der Datenbank, die Adresse des Servers. Solange nur Sie die Anwendung starten, geht das gut. Der Grundsatz lautet: Was sich zwischen Umgebungen unterscheidet, gehört nicht in den Code.
4:25 Auf Ihrem Rechner heißt die Datenbank vielleicht anders als auf dem Testsystem, und auf dem Produktivsystem noch einmal anders. Wer das im Quelltext stehen hat, muss für jede Umgebung neu übersetzen — und das ist der sicherste Weg, um irgendwann eine Testversion produktiv laufen zu haben. Java kann Eigenschaftsdateien von Haus aus lesen, ohne Zusatzbibliothek.
4:46 Ein schlichtes Format aus Schlüssel und Wert, das seit Jahrzehnten funktioniert und das jeder Betreiber kennt. Zwei Zeilen, mehr braucht es hier nicht. Wichtig ist der Ort: das Ressourcenverzeichnis der Maven-Struktur. Alles, was dort liegt, wandert beim Bauen mit ins Archiv und ist zur Laufzeit über den Klassenpfad erreichbar.
5:05 Das ist bequem und hat eine Kehrseite, die wir gleich bei den Stolpersteinen ansprechen: Diese Datei ist Teil der Auslieferung. Für Werte wie einen Dateinamen ist das genau richtig. Für Zugangsdaten ist es das Gegenteil von richtig — die gehören in eine Datei außerhalb der Anwendung oder in Umgebungsvariablen. Zehn Zeilen, und wieder begegnen uns Muster, die Sie inzwischen kennen.
5:28 Die Ressourcenverwaltung mit automatischem Schließen — dieselbe Schreibweise wie bei den Datenbankverbindungen im dritten Modul. Und die Übersetzung einer geprüften Ausnahme in eine ungeprüfte, weil man hier ohnehin nichts retten kann: Fehlt die Konfiguration, ist die Anwendung nicht startfähig, und dann soll sie das auch deutlich sagen.
5:47 Ein Detail noch: Der führende Schrägstrich beim Dateinamen sucht im Wurzelverzeichnis des Klassenpfads. Ohne ihn wird relativ zum Paket gesucht, und dann finden Sie nichts. Sie haben gesehen, wie es geht — jetzt machen Sie dasselbe mit der Serveradresse. Sie steht noch fest im Code, mitsamt Port. Erfolgreich sind Sie, wenn eine Änderung in der Eigenschaftsdatei wirkt, ohne dass Sie neu übersetzen müssen. Genau dieser Test ist der eigentliche Punkt der Aufgabe.
6:14 Es geht nicht darum, den Wert irgendwie herauszuziehen, sondern darum, den Kreislauf einmal zu erleben: Datei ändern, starten, anderes Verhalten. Das ist der Unterschied zwischen Konfiguration und einer Konstante, die zufällig in einer anderen Datei steht. Der erste Punkt ist der wichtigste und betrifft Sicherheit: Zugangsdaten in einer Datei, die mit ins Archiv und in die Versionsverwaltung wandert.
6:38 Das passiert schnell und ist schwer rückgängig zu machen, denn die Versionsverwaltung vergisst nicht. Der zweite ist tückisch: Ein fehlender Schlüssel liefert keinen Fehler, sondern einen leeren Wert — und die Anwendung läuft mit nichts weiter. Wer streng sein will, prüft das ausdrücklich. Der dritte ist die Ressourcenfrage.
6:56 Und der vierte mahnt zum Maß: Alles auslagern, auch was sich nie ändert, macht die Anwendung nicht flexibler, nur unübersichtlicher.
Abhängigkeiten zentral verwalten
7:05 Jetzt räumen wir die Projektdateien auf. Sie erinnern sich: Beim Anlegen des Servermoduls haben wir Abhängigkeiten kopiert, und ich hatte gesagt, das stört zu Recht. Genau darum geht es jetzt — und es ist mehr als Kosmetik. Zwei Werkzeuge stehen zur Verfügung. Das erste kennen Sie schon: Eigenschaften, also benannte Werte. Hebt man sie ins Eltern-Projekt, gelten sie für alle Module.
7:28 Das zweite ist neu und geht weiter. Es gibt einen Abschnitt, der Abhängigkeiten nicht einbindet, sondern nur beschreibt — eine Art Vorlage. Dort legen Sie Version und Geltungsbereich fest, und die Module nennen dann nur noch Herausgeber und Namen. Der entscheidende Zusatz steht am Ende: Das gilt auch für Bibliotheken, die gar nicht Sie einbinden, sondern die über andere Abhängigkeiten mitkommen.
7:53 Wichtig ist der Unterschied, den man beim ersten Lesen leicht übersieht: Dieser Abschnitt bindet nichts ein. Er sagt nur, was gelten soll, falls jemand diese Bibliothek benutzt. Das Untermodul muss sie weiterhin ausdrücklich nennen — dann aber ohne Version und ohne Geltungsbereich. Der Gewinn liegt auf der Hand: Ein Versionssprung passiert an einer Stelle, und die Entscheidung, dass eine bestimmte Bibliothek nur zur Laufzeit gebraucht wird, steht dort, wo sie begründet wurde.
8:19 Nicht dreimal an Orten, wo sie zufällig auch stimmt. Diese Übersicht ist die Antwort auf die Frage, die beim Aufräumen jedes Mal aufkommt: Wo trage ich was ein? Die Faustregel steckt in der letzten Zeile. Eine Bibliothek, die nur ein einziges Modul benutzt, darf ihre Version dort behalten — das ist keine Sünde. Manche Projekte ziehen trotzdem alles zentral, weil sich das morgen ändern könnte. Beides ist vertretbar; unschön wird es nur, wenn im selben Projekt beides gemischt vorkommt.
8:49 Und die Fußnote weist auf eine Abkürzung hin: Manche Anbieter veröffentlichen eine Stückliste, die alle ihre Bausteine aufeinander abstimmt. Der dritte Punkt ist der eigentlich schwerwiegende: zwei Stände derselben Bibliothek im selben Lauf. Das passiert schneller, als man denkt — eine Abhängigkeit zieht eine ältere Version mit, Sie deklarieren eine neuere, und was am Ende geladen wird, entscheidet die Reihenfolge im Klassenpfad.
9:15 Der Fehler äußert sich dann als fehlende Methode zur Laufzeit, obwohl alles sauber übersetzt hat. Solche Fehler kosten Nachmittage. Die zentrale Verwaltung räumt das ab, indem sie festlegt, welcher Stand gilt — unabhängig davon, wer die Bibliothek ins Spiel gebracht hat. Der erste Punkt ist die Verwechslung, über die wir gerade gesprochen haben: Der Verwaltungsabschnitt bindet nichts ein, er beschreibt nur.
9:38 Wer glaubt, damit sei die Abhängigkeit da, wundert sich über fehlende Klassen. Der zweite ist der Klassiker beim Aufräumen: Die Version bleibt aus Versehen im Untermodul stehen, und die lokale Angabe gewinnt — die zentrale Verwaltung wirkt dann für dieses Modul einfach nicht. Der dritte ist die mitgezogene Bibliothek, die man direkt anspricht. Und der vierte: Nach so einem Umbau gehört ein voller Build über die Kommandozeile dazu.
Ein lauffähiges JAR bauen
10:03 Und damit sind wir bei der letzten technischen Frage dieses Seminars: Wie kommt die Anwendung eigentlich auf einen anderen Rechner? Der Build erzeugt zwar Archive, aber die enthalten nur unseren eigenen Code — und der allein läuft nirgendwo. Das Problem ist der Klassenpfad. Unsere Anwendung braucht ein gutes Dutzend Bibliotheken, und die müssen beim Start alle auffindbar sein.
10:25 In der Entwicklung erledigen Maven und die Entwicklungsumgebung das für uns. Auf einem Server ist niemand da, der das tut. Eine Lösung ist ein Container, in dem alles zusammen liegt — völlig legitim und heute weit verbreitet. Wir gehen den anderen Weg: ein einziges Archiv, das den eigenen Code und alle Bibliotheken enthält. Zum Starten genügt dann ein passendes Java und ein Befehl.
10:49 Das Plugin sammelt alle Klassen ein — Ihre eigenen und die aus den Bibliotheken — und schreibt sie in ein gemeinsames Archiv. Zwei Einstellungen sind nötig, und beide lösen konkrete Probleme. Die erste trägt die Hauptklasse ein, damit Java weiß, wo es starten soll. Die zweite kümmert sich um einen unangenehmen Nebeneffekt: Verschiedene Bibliotheken bringen gleichnamige Konfigurationsdateien mit, und beim Zusammenschütten würde eine die andere überschreiben.
11:15 Diese Einstellung mischt sie stattdessen. Ohne sie funktioniert das Archiv scheinbar — und fällt dann an einer Stelle aus, die niemand mit dem Verpacken in Verbindung bringt. Ein Befehl zum Bauen, ein Befehl zum Starten. Beachten Sie die Fußnote: Im Zielverzeichnis liegen jetzt zwei Archive. Das eine mit dem Zusatz enthält nur Ihren Code — das ist das schlanke, das ohne den Rest nicht startet. Das andere ist das vollständige. Genau dieses geben Sie weiter.
11:42 Und wenn Sie es ausprobieren, achten Sie auf die Ausgabe: Es ist dieselbe Anwendung mit derselben Protokollierung, die Sie eben noch in der Entwicklungsumgebung gestartet haben. Nur eben ohne Entwicklungsumgebung. Das ist ein guter Moment, um kurz innezuhalten. Die letzte Aufgabe dieses Seminars. Bauen Sie das vollständige Archiv und starten Sie es von der Kommandozeile.
12:05 Erfolgreich sind Sie, wenn ein Abruf dieselben Daten liefert wie zuvor aus der Entwicklungsumgebung. Ein praktischer Hinweis vorweg, weil er die häufigste Stolperfalle ist: Beenden Sie vorher den Server in der IDE, sonst ist der Port belegt und Sie suchen an der falschen Stelle. Und wenn Sie es genau wissen wollen: Kopieren Sie das Archiv in ein anderes Verzeichnis und starten Sie es von dort. Dann sehen Sie, ob wirklich alles drin ist.
12:30 Der erste Punkt ist die Verwechslung der beiden Archive — das schlanke auszuliefern und dann den Klassenpfad von Hand zusammenzusuchen, ist mühsam und fehleranfällig. Der zweite ist das eben besprochene Überschreiben gleichnamiger Dateien; die Fehlermeldung führt einen dabei in völlig falsche Richtungen. Der dritte ist die fehlende Hauptklasse, und immerhin ist diese Meldung eindeutig. Und der vierte betrifft die Versionsverwaltung: Das große Archiv gehört nicht hinein.
12:56 Es ist Ergebnis des Builds und lässt sich jederzeit neu erzeugen — genau wie das Zielverzeichnis, über das wir im ersten Modul gesprochen haben.
Wie es weitergeht
13:04 Damit ist Kursradar fertig — gebaut, konfigurierbar und auslieferbar. Nutzen wir die letzten Minuten für die Frage, die nach jedem Seminar kommt: Wie geht es weiter? Und zwar sowohl mit diesem Projekt als auch mit Ihnen. Schauen wir kurz auf das, was jetzt da ist: drei Module, eine externe Schnittstelle, eine Datenbank, eine REST-Schnittstelle und ein auslieferbares Paket.
13:28 Das ist eine kleine Anwendung — aber sie ist vollständig. Und das ist der eigentliche Wert für Ihr weiteres Lernen. An einem Beispiel mit fünfzehn Zeilen kann man keine echten Fragen stellen. An diesem Bestand schon: Wo gehört diese neue Funktion hin? Welches Modul darf welches kennen? Was passiert, wenn ich die Datenbank austausche? Solche Fragen beantwortet man nur, indem man es versucht.
13:52 Diese fünf Ideen sind nach Aufwand sortiert, ungefähr jedenfalls. Und sie haben etwas gemeinsam, das in der Fußnote steht: Jede berührt mehrere Module. Genau das macht sie als Übung wertvoll. Ein Endpunkt zum Löschen sieht nach einer Zeile aus und zwingt Sie doch, die Schnittstelle, die Umsetzung und die Ressource anzufassen.
14:12 Der Wechsel auf eine echte Datenbank ist die interessanteste Aufgabe von allen — dort merken Sie, ob die Abstraktion aus Modul drei wirklich trägt. Meine Empfehlung wäre trotzdem: Nehmen Sie sich eine vor, nicht drei. Fünf Empfehlungen zum Schluss. Die erste ist die unbequemste: eine Sache zu Ende bringen, bevor die nächste anfängt.
14:32 Der zweite Punkt betrifft Rahmenwerke — irgendwann führt kein Weg daran vorbei, und meist entscheidet ohnehin das Projekt, in dem Sie landen. Der dritte und vierte sind Handwerk: der Sprachstand und das Testen jenseits von Einheitentests. Und der fünfte ist der, über den man streiten kann. KI-Werkzeuge sind eine echte Hilfe — als Prüfinstanz, die Ihren Code hinterfragt. Als Ersatz fürs Selberschreiben nehmen sie Ihnen genau die Übung weg, um die es hier ging.
15:00 Vier Punkte zum Abschluss, und sie sind eher Haltungsfragen als technische Details. Ein Rahmenwerk lernen, bevor die Grundlagen sitzen — dann bleibt Konfiguration Abschreiben. Erweiterungen planen statt eine davon fertig zu bekommen; ein halbfertiges Projekt lehrt weniger als ein kleines fertiges. Die eingebettete Datenbank im Dauerbetrieb einsetzen — dafür ist sie nicht gebaut, und das ist keine Kritik an ihr.
15:25 Und der letzte Punkt ist der ehrlichste: Code erzeugen lassen und ihn für verstanden halten. Das merkt man erst, wenn er nicht funktioniert.
Kursradar ist auslieferbar
15:34 Damit sind wir am Ende. Wir haben eine einheitliche Protokollierung über alle Bibliotheken hinweg, eine Konfiguration außerhalb des Codes, Versionen an einer zentralen Stelle und ein einziges Archiv, das auf jeder Maschine mit passendem Java startet. Vor allem aber haben Sie den ganzen Weg einmal selbst gebaut — vom leeren Projekt bis zur auslieferbaren Anwendung, ohne dass ein Rahmenwerk Ihnen Entscheidungen abgenommen hätte.
15:57 Wenn Sie sich als Nächstes eines ansehen, werden Sie vieles wiedererkennen. Und das ist genau der Punkt. Viel Erfolg mit Ihrem nächsten Java-Projekt.
Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →