adesso Blog

Die Sprache Java und das JDK-Ökosystem sind voller verborgener Schätze. Diese zu entdecken erfordert eine kleine Expedition durch einige JDK Enhancement Proposals, JEPs genannt. In diesem Blog-Artikel begeben wir uns auf eine Expedition und entdecken Code-Snippets in JavaDoc sowie den beschleunigten Start einer Anwendung mit AppCDS.

Java Snippets in JavaDoc

In den meisten Fällen werden Programme entwickelt, die über Jahre gepflegt und gewartet werden müssen. Solche Programme benötigen eine solide Dokumentation, insbesondere wenn sie in anderen Kontexten wiederverwendet werden sollen. Aus diesem Grund wurde bereits in der ersten Version des JDK das Tool javadoc eingeführt. Mit javadoc können Kommentare im Quellcode in eine durchsuchbare HTML-Schnittstellen-Dokumentation umgewandelt werden.

In solchen technischen Dokumenten ist es sinnvoll, die beabsichtigte Verwendung der Schnittstelle zu skizzieren. Zu diesem Zweck wird oft der @code-Tag verwendet, der den Source Code hervorhebt. Leider ist das @code-Tag nicht gut für mehrzeilige Codepassagen geeignet. Dies hat sich seit Java 18 mit dem neuen @snippet-Tag geändert. Im folgenden Listing wird die Verwendung des @snippet-Tags für die Klasse MwStRechner demonstriert. In der fertigen Dokumentation bleibt die Formatierung erhalten, nur mehrzeilige Kommentare sind nicht erlaubt.

	
	/**
		 * Berechnung der MwSt für einen Privatkunden beim Einkauf in Höhe von 1055
		 * {@snippet :
		 *   var kunde = new Privatkunde("Merlin", "");
		 *   var wert = 1055d;
		 *   // ...
		 *   var mwst = MwStRechner.PlainOOP.calculateMwSt(kunde, wert);
		 * }
		 */
	

Leider kann der Code nicht getestet werden und kann Syntaxfehler enthalten. Um dieses Problem zu lösen, können Teile von Java-Dateien mit dem @snippet-Tag eingebunden werden. Innerhalb der zugrundeliegenden Dateien können Transformationen definiert werden, um die Lesbarkeit und Aussagekraft zu verbessern. Dazu gehören unter anderem:

  • Ersetzen von Text durch anderen Text
  • Hervorhebungen durch Regex-Ausdrücke
  • Definitionen von Bereichen

Eine vollständige Liste findet sich in JEP 412 [1]. Das folgende Listing zeigt ein vollständiges Beispiel, wie ein Bereich aus der Datei snippet-files/SwitchExpressionsSnippets.java in das JavaDoc einer anderen Klasse eingebunden werden kann.

	
	/ Datei: MwStRechner.java
		/**
		 * Berechnung der MwSt für einen Privatkunden beim Einkauf in Höhe von 1055
		 * {@snippet file="SwitchExpressionsSnippets.java" region="example"}
		 */
		// Datei: snippet-files/SwitchExpressionsSnippets.java
		class Snippets {
		  void snippet01() {
		    // @start region="example"
		    // @replace region="replace" regex='(= new.*;)|(= [0-9]*d;)' replacement="= ..."
		    // @highlight region="highlight" regex="\bMwStRechner\b"
		    var kunde = new Privatkunde("Merlin", "test@other.de"); // @replace regex="var" replacement="Kunde"
		    var wert = 1055d; // @replace regex="var" replacement="double"
		    /* .. */
		    var mwst = MwStRechner.PlainOOP.calculateMwSt(kunde, wert); // @link substring="PlainOOP.calculateMwSt" target="MwStRechner.PlainOOP#calculateMwSt"
		    // @end @end @end
		  }
		}
	

Generiertes JavaDoc mit den Ersetzungen und Herforhebungen

In diesem Beispiel habe ich Bereiche ersetzt und markiert. Das Endergebnis gibt einen guten Überblick über die Verwendung und kann regelmäßig getestet werden. Mit diesem weniger bekannten, aber mächtigen Werkzeug des Java-Ökosystems lässt sich die klar strukturierte Schnittstellendokumentation sehr einfach mit Beispielen anreichern.

Dynamic App Class Data Sharing

Die Java Virtual Machine (JVM) wurde zu einer Zeit entwickelt, in der die Spitzenleistung von lang laufenden Anwendungen viel relevanter war als in der heutigen Microservice-getriebenen Zeit. Einige der damals besten Heuristiken wirken sich heute negativ auf die Performance von Microservices aus. Sie sind der Grund für die vergleichsweise schlechte Startperformance der JVM.

Um die Startperformance einer JVM-Anwendung zu verbessern, ist es notwendig, den initialen Classloading-Prozess zu beschleunigen. In diesem Schritt des JVM-Starts werden Informationen über die verwendeten Klassen geladen und analysiert. Um die Wiederholung dieses Schrittes zu vermeiden, wurde die JVM um das Prinzip des Class Data Sharing (CDS) erweitert. Bei CDS werden die gesammelten Informationen aus dem Classloading in einem CDS-Archiv persistiert und können zu einem späteren Zeitpunkt wieder verwendet werden.

Die JVM enthält bereits ein Archiv mit der Java-Standardbibliothek. Das Archiv befindet sich als `classes.jsa` Datei im Teil der ausgelieferten JVM und wurde mit einer für G1 konfigurierten JVM mit 128MB Heapspace erstellt. Falls eine andere Heap-Konfiguration oder weitere Klassen benötigt werden, muss ein eigenes Archiv erstellt werden. Mit Application Class-Data Sharing, auch AppCDS genannt, kann auch der Classpath einer Anwendung in die erzeugten CDS-Archive übernommen werden. Dadurch kann die Startzeit der JVM erheblich verkürzt werden. Wenn ihr die gleiche Anwendung auf mehreren JVMs betreibt oder häufig neu startet, erhöht sich die Ersparnis enorm.

Um ein CDS-Archiv zu erstellen, benötigt man Informationen über die Klassen, die zur Laufzeit in einer Anwendung verwendet werden. Diese Informationen können von der JVM selbst ermittelt werden:

  • Ein Trainingslauf, bei dem die Anwendung mit zusätzlichen Parametern gestartet wird.
    • 1. Mit -Xshare:off -XX:DumpLoadedClassList=clazzes.cls wird die Applikation gestartet und eine Liste der geladenen Klassen als Datei clazzes.cls erzeugt.
    • 2. mit -Xshare:dump -XX:SharedArchiveFile=MyApp.jsa -XX:SharedClassListFile=clazzes.cls -cp app.jar wird ein CDS-Archiv der Applikation in der Datei MyApp.jsa erzeugt.
  • Per JCMD kann ein CDS-Archiv in Produktion bestimmt werden, dazu muss.
    • 1. muss die Applikation mit dem Parameter -XX:+RecordDynamicDumpInfo gestartet werden.
    • 2. Der Befehl jcmd <pid> VM.cds dynamic_dump my_dynamic_archive.jsa d erzeugt ein CDS-Archiv VM.cds für die angegebene PID.
  • Die JVM kann automatisch nach dem Beenden ein CDS-Archiv erzeugen. Dazu wird beim Start der Parameter -XX:ArchiveClassesAtExit=MyApp.jsa angegeben.

Um eine Anwendung mit dem generierten CDS-Archiv zu starten und von den gesammelten Informationen zu profitieren, muss die JVM mit dem Parameter -XX:SharedArchiveFile=MyApp.jsa gestartet werden. Mit diesen wenigen zusätzlichen Schritten lässt sich die Startleistung einer JVM-Anwendung deutlich verbessern. Gleichzeitig kann man früher von der hohen Peak-Performance profitieren. Mit diesen Anpassungen ist die JVM auch für Umgebungen gewappnet, in denen die JVM neu gestartet werden muss.

Zusammenfassung

In diesem Blog-Beitrag habe ich zwei weniger bekannte Werkzeuge aus dem Java-Ökosystem vorgestellt. Mit Hilfe dieser Werkzeuge lassen sich schnell startende und ressourcenschonende Anwendungen mit eleganten und gut dokumentierten Schnittstellen entwickeln. Unter anderem zu diesem Thema halte ich Vorträge auf Konferenzen und schreibe weitere Beiträge adesso Blog. Bei Fragen und Problemen stehen ich oder unsere Expertinnen und Experten von adesso gerne zur Verfügung.

Bild Merlin Bögershausen

Autor Merlin Bögershausen

Merlin Bögershausen ist Software Entwickler, Speaker und Author bei adesso am Standort Aachen. Er beschäftigt sich mit Neuerungen im Java-Universum und der Softwareentwicklung im Public-Bereich.

Diese Seite speichern. Diese Seite entfernen.