GraalVM kann aus Java-Bytecode ein natives Image, also nativen Maschinencode, erstellen. Damit erhält man ein normales Executable, das keine Abhängigkeit zur JVM hat, deutlich schneller startet und einen geringeren Ressourcenverbrauch hat.
Zum Test erstellen wir fix ein einfaches Java Hello World.
Hello.java
public class Hello {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Manifest.txt
Manifest-version: 1.0
Main-Class: Hello
Java-Code kompilieren und jar erstellen:
$ javac Hello.java
$ jar cfm Hello.jar Manifest.txt Hello.java
$ java -jar Hello.jar
Hello World!
Das native Image kann mit dem GraalVM-Tool native-image
erstellt werden:
$ native-image -jar Hello.jar
Build on Server(pid: 8912, port: 26682)
classlist: 350.53 ms
(cap): 605.69 ms
setup: 856.57 ms
(typeflow): 4,224.92 ms
(objects): 1,103.80 ms
(features): 29.86 ms
analysis: 5,452.54 ms
universe: 195.50 ms
(parse): 917.86 ms
(inline): 783.22 ms
(compile): 5,169.52 ms
compile: 7,097.16 ms
image: 437.47 ms
write: 115.94 ms
[total]: 14,536.87 ms
$ ./Hello
Hello World
Die erzeugte Executable ist mit 5,4 Mb nicht gerade klein, enthält aber auch alle verwendeten Teile der Java Runtime schon precompiled.
Die schlechte Nachricht ist, dass dies nicht mit allem funktioniert. Einige Klassen können offenbar nicht kompiliert werden. Bei meinem Versuch ein einfaches Swing-Beispiel zu kompilieren, wurde ich darauf hingewiesen, dass sun.misc.URLClassPath$JarLoader
unsupported ist:
Build on Server(pid: 9251, port: 26682)*
classlist: 1,526.88 ms
(cap): 990.22 ms
setup: 2,164.54 ms
analysis: 19,376.53 ms
error: unsupported features in 3 methods
Detailed message:
Error: Must not have a started Thread in the image heap.
Trace: object sun.java2d.opengl.OGLRenderQueue
field sun.java2d.opengl.OGLRenderQueue.theInstance
Error: Unsupported type sun.misc.URLClassPath$JarLoader is reachable
...
Ergibt ja auch Sinn, dass ein JarLoader nicht mit reinem nativen Code ohne JVM funktioniert. Wer also hofft seine lieblings IDE, die dank Java fett und träge ist, zu einem schnellen nativen Kompilat umzuwandeln, der wird leider enttäuscht (und wehe mir sagt jemand, dass Visual Studio oder XCode gar nicht Java verwenden).
Sprachen die innerhalb einer virtuellen Maschine laufen gibt es viele, wie beispielsweise Java, Python oder JavaScript. Dabei hat jede Sprache meistens ihre eigene VM, die speziell für ihre Sprache entworfen wurde. Andere Sprachen laufen dann entweder gar nicht in dieser VM, oder mit geringer Performance.
Nach jahrelanger Entwicklungsarbeit hat Oracle nun GraalVM vorgestellt, eine universale VM, die nicht speziell für eine Zielsprache designed ist, sondern unterschiedliche Programmiersprachen gleich gut mit ähnlicher Performance unterstützt. Dabei sind zur Laufzeit die Datenstrukturen der Sprachen auch kompatibel, wodurch es ohne Overhead möglich ist, Funktionen einer anderen Sprache aufzurufen.
Aktuell unterstützt werden JVM basierte Sprachen sowie JavaScript und LLVM-Bitcode. Bisher nur experimentell werden außerdem Ruby, R und Python unterstützt. Damit ist es also problemlos möglich, Rust oder C++-Code, der zu LLVM-Bitcode kompiliert wurde, mit Java oder JavaScript zu mischen. Die völlige Wahlfreiheit der Programmiersprache, ohne dabei durch Performance oder Verfügbarkeit von Bibliotheken beschränkt zu sein, ist tatsächlich ein interessantes Versprechen.
Auch interessant ist die Möglichkeit, Java-Anwendungen zu einem nativen Image zu kompilieren, was die Startzeit drastisch verkürzt und den Speicherverbrauch senkt.
Technisch gesehen setzt GraalVM auf einer normalen JVM auf, mit einem komplett neuen JIT-Compiler und APIs, über die neue Sprachen wie JavaScript in GraalVM eingebunden werden können. Oracle hat dabei die Hoffnung, dass Third-Party-Entwickler ihre Programmiersprachen für GraalVM adaptieren. Ich kann mir jedoch vorstellen, dass viele beim Thema Java bzw JVM erstmal skeptisch sind, ganz unabhängig von Oracle und irgendwelchen juristischen Fragen. Die JVM gilt nicht als besonders schlank, die Startzeiten von Java-Anwendungen sind zu lang und der Speicherverbrauch ist hoch. Auf dem Desktop gibt es kaum noch Java-Anwendungen, bis auf die paar Entwicklungsumgebungen.
GraalVM Webseite
Download
Beispiele
Apache Tomcat 9.0.4 wurde veröffentlicht, was auch die erste stabile Version der 9er Reihe ist.
Tomcat 9 implementiert die neueren Spezifikationen Java Servlet 4.0, JavaServer Pages 2.4, Java Unified Expression Language 3.1 und die Java API for Websocket 2.0. Des Weiteren wird jetzt auch mindestens Java 8 benötigt.
Downloads gibt es auf der Apache Tomcat Webseite.
LDAP-Server gibt es einige. Am meisten verbreitet ist wohl OpenLDAP. Ich persöhnlich finde OpenLDAP allerdings zu frickelig, vor allem seit slapd.conf abgeschafft wurde, und die Konfiguration auch über ldap geschieht. Glücklicherweise gibt es einige Alternativen, z.B. den 389 Directory Server von Red Hat, und natürlich OpenDJ, worum es in diesem Artikel auch gehen soll.
OpenDJ ist ein Fork von OpenDS, einem von Sun Microsystems in Java entwickelten LDAP-Server. Nach der Übernahme von Sun durch Oracle wurde die Entwicklung von OpenDS jedoch eingestellt, daher gründeten ehemalige Sun-Mitarbeitern die Firma ForgeRock und forkten OpenDS. OpenDJ hat daher einen gewissen kommerziellen Charakter, allerdings ist es trotzdem OpenSource-Software.
OpenDJ gibt es unter anderem als einfaches zip-Package zu downloaden. Für die normalen Releases muss man sich registrieren, jedoch nicht für die Nightly-Builds. Da es sich um Java-Software handelt, benötigt man natürlich eine JRE. Nach dem Download einfach das zip-Package in den gewünschten Installationsort entpacken. Danach muss nur noch das setup-Script ausgeführt werden. Dieses startet einen kinderleichten grafischen- oder CLI-Assistenten, in dem alles nötige konfiguriert wird.
Nach dem Setup wird gewöhnlich eine Server-Instanz gestartet und es wird gefragt, ob man das Control-Panel (Button mit der Aufschrift "Steuerbereich starten") starten möchte. Dies kann man später auch alles manuell machen. Im opendj/bin Verzeichnis liegen alle nötigen Skripte (start-ds, stop-ds, control-panel).
Das Control-Panel macht OpenDJ so benutzerfreundlich. Es ist sowohl möglich lokale Server, als auch entfernte Server damit zu administrieren.
Neben typischen Aufgaben wie LDIF Im- und Export und Schema-Verwaltung, gibt es auch die Möglichkeit, LDAP-Einträge zu verwalten. Man kann sich also auch einen separaten LDAP-Client sparen.
Ganz nett ist auch, dass OpenDJ standardmäßig mit allen wichtigen Schemas ausgeliefert wird. Einfacher kann man den Einstieg in die LDAP-Welt nicht machen.
Möchte man, dass eine Java-Webanwendungen auf verschiedenen Applicationservern oder Servletcontainern lauffähig ist, gibt es im Bezug auf JNDI einen kleinen Fallstrick. Die JNDI-Namen für Resourcen sind nämlich nicht überall gleich. Mit folgendem Code kann man unter Glassfish auf einen vom Applicationserver zur Verfügung gestellten Connection-Pool zugreifen:
InitialContext context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("jdbc/mydb");
Connection connection = dataSource.getConnection();
Mit anderen Servern, wie z.B. Apache Tomcat, funktioniert dies jedoch nicht. Statt dem String "jdbc/mydb"
müsste man dort "java:comp/env/jdbc/mydb"
verwenden. Das wiederum funktioniert nicht mit Glassfish, zumindestens nicht ohne weiteres. Allerdings gibt es dafür eine Lösung.
Man verwendet folgenden Java-Code.
DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/mydb");
Dazu muss man dann noch den Standard Deployment Descriptor web.xml und die glassfish-web.xml anpassen. In die web.xml wird folgendes eingefügt:
<resource-ref>
<res-ref-name>jdbc/mydb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
und in die glassfish-web.xml das:
<resource-ref>
<res-ref-name>jdbc/mydb</res-ref-name>
<jndi-name>jdbc/mydb</jndi-name>
</resource-ref>
Danach funktioniert die Webapp sowohl mit Glassfish als auch mit Tomcat, wenn im Server die nötigen JNDI-Resourcen konfiguriert sind.
Kommentare
Rudi | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Peter | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Damit wird Nedit durch XNedit ersetzt.
Danke!
Olaf | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Anti-Aliasing hängt von der Schriftart ab. Mit einem bitmap font sollte die Schrift klassisch wie in nedit aussehen.
Einfach unter Preferences -> Default Settings -> Text Fonts nach einer passenden Schriftart suchen.
Peter | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Mettigel | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Ich hatte gedacht, dass der GX-415 im s920 deutlich mehr Dampf hat als der Raspi4.
Mein Thinclient verbraucht mit 16 GB RAM ~11 W idle, das ist das Dreifache vom RP4. Das muss man dem kleinen echt lassen... Sparsam ist er.
Olaf | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Ergebnisse von der Ultra 80 wären natürlich interessant, insbesondere im Vergleich mit dem rpi1.
kosta | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
ich hätt hier zugriff auf Ultra-80 4CPU 4GB 2x Elite3D.
RO | Artikel: Benutzt bitte nur noch Unicode!
Sehe ich genauso.