Java in EXE-Dateien konvertieren —
Warum? Wann? Wann nicht? Und wie?

Von Dmitry LESKOV LinkedIn

Letzte Aktualisierung: 23. Juli 2014
Originalartikel auf Englisch | Auch verfügbar in: Français
Wenn Sie sicher sind, dass Sie eine echte EXE-Datei brauchen, folgen Sie direkt diesem Link: AOT Compilers.

"Wie erzeuge ich aus meiner Java-Anwendung eine EXE-Datei?", "Brauche Hilfe bei der Konvertierung von JAR in EXE", "Kann man mit Java eine ausführbare Windows-Datei erstellen?" — Diese und ähnliche Fragen gehören zu den häufigsten Themen in Java-Entwicklerforen. Würden Sie heute ein solches Thema eröffnen, hätten Sie wahrscheinlich die folgenden drei Arten von Antworten erhalten:

  • "Das geht nicht"
  • "Das sollten Sie nicht tun, denn das widerspricht schließlich dem Sinn und Zweck von Java"
  • "Sie brauchen dafür die Drittanbietersoftware X und Y"

Die Wahrheit ist, dass es vollkommen unterschiedliche Ansätze gibt, um native ausführbare Dateien aus Java-Anwendungen zu erstellen. Außerdem lassen sich unter bestimmten Bedingungen einige der Probleme auch ohne die Generierung einer EXE-Datei lösen. Die richtige Antwort auf einen solchen Post wäre also, weitere Informationen anzufordern und nachzufragen, welches Ziel mit der Umwandlung in EXE verfolgt wird. Meistens geht es um folgende Problematik:

Java kompiliert plattformunabhängigen Bytecode (CLASS-Dateien), der von der PC-Hardware nicht direkt unterstützt wird. Also benötigt man für die Ausführung eines Java-Programms eine Java-Laufzeitumgebung (JRE, Java Runtime Environment), die entweder die Bytecodeanweisungen interpretiert oder umgehend in nativen Code kompiliert. Dies wiederum bedeutet, dass der Autor des Programms irgendwie sicherstellen muss, dass die richtige JRE-Version auf dem System jedes Endanwenders installiert ist.

In Allgemeinen können Sie nicht erwarten, dass Ihre Endanwender wissen, was eine JRE ist, wie sie prüfen können, welche Version installiert ist, oder wie sie die JRE herunterladen und installieren. Dies gilt insbesondere für Anwendungen wie Spiele oder Multimedia-Anwendungen. Und diejenigen, die bereits eine JRE installiert haben, werden wahrscheinlich wenig begeistert sein, wenn sie eine zweite Version installieren sollen, weil sie dann befürchten müssen, dass ihre vorhandenen Java-Anwendungen und Lieblingsapplets nicht mehr funktionieren.

Doch selbst wenn Sie sicherstellen können, dass die richtige JRE-Version auf allen Endanwendersystemen ordnungsgemäß installiert ist, was in einer Schulungs- oder Unternehmensumgebung durchaus möglich ist, kann die Befehlszeile zum Starten Ihrer Java-Anwendung ziemlich lang sein:

    java -Xmx200m -cp whatever.jar -Dsome.property MyApp

Natürlich können Sie die Zeile in einer Batchdatei mit dem Namen runme.bat speichern, aber es sieht doch wesentlich einfacher aus, wenn Sie Freunden, Lehrern oder Kollegen Ihr Programm in Form einer einzelnen Datei übergeben, die sich per Doppelklick ausführen lässt. Noch besser wäre es, wenn die Installation und Deinstallation auf native Weise erfolgen würden, ohne andere Anwendungen zu beeinflussen.

Folglich ist es kaum überraschend, dass die Hauptmotivation für die Suche nach einer Möglichkeit zur Konvertierung von Java-Anwendungen in EXE-Dateien darin besteht, die Bereitstellung und Nutzung für den durchschnittlichen Anwender, sprich den Windows-Anwender, einfacher und sicherer zu machen. Was jedoch die Neulinge unter den Java-Entwicklern überrascht, ist die Tatsache, dass das Java Development Kit (JDK) keine entsprechende Funktionalität bietet (außer für JavaFX-Anwendungen — siehe unten.) Bevor Version J2SE 1.4 auf den Markt kam, konnte man mit den JDK-Tools nicht mehr erzeugen als

Damit Ihre Java-Anwendung per Doppelklick ausgeführt werden kann, müssen Sie sie in eine sogenannte ausführbare JAR-Datei packen. Dazu spezifizieren Sie die Hauptklasse Ihrer Anwendung sowie alle eventuell erforderlichen zusätzlichen JAR-Dateien im Manifest der JAR-Datei:

    Main-Class: MyAppMain
    Class-Path: mylib.jar

Anschließend verwenden Sie das Dienstprogramm jar aus dem Java-SDK, um Ihre Klassen und Ressourcendateien unter Angabe der Option m und des Namens Ihrer Manifest-Datei zu packen:

    jar cvfm MyApp.jar MyApp.mf *.class *.gif

Daraufhin wird die Datei MyApp.jar erzeugt. Wenn Sie nun den Befehl

    java -jar MyApp.jar

eingeben, liest der Java-Launcher das Manifest aus der Datei MyApp.jar und ruft die Methode main der Klasse MyAppMain auf. Auf einem System mit installierter JRE können Sie auf die JAR-Datei doppelklicken, um den Java-Launcher automatisch aufzurufen.

Hinweis: JAR-Dateien sind unter Windows mit dem Launcher javaw verknüpft, der keine Konsole beim Starten öffnet. Wenn Ihre Anwendung eine Konsole erfordert, müssen Sie eine Batchdatei schreiben, um die Anwendung über den Launcher java zu starten.

Für Anwendungen, die aus mehreren JAR-Dateien bestehen, gibt es das Open-Source-Tool One-JAR, das den Anspruch erhebt, mehrere JAR-Dateien richtig in eine einzige Datei zu packen.

Das Hauptproblem im Zusammenhang mit ausführbaren JAR-Dateien ist die Kompatibilität. Möglicherweise ist nicht die für Ihre Anwendung erforderliche Version der JRE installiert oder die benötigten Java Optional Packages (ehemals Standard Extensions) sind nicht vorhanden. Wenn Ihre Anwendung beispielsweise die neuesten Funktionen von JDK 8 nutzt, wird sie mit der JRE 7 oder früheren Versionen nicht laufen.

Glücklicherweise hat Sun Microsystems damals eine Bereitstellungstechnologie für Java-Anwendungen entwickelt, die dieses Kompatibilitätsproblem löst und einige nette Zusatzfunktionen bietet. Sie ist seit Version 1.4 Bestandteil der Java-Plattform und heißt

Ausführbare JAR-Dateien

Vorteile

Keine Drittanbietertools erforderlich

Eine einzige Datei für alle Java-kompatiblen Plattformen

Nachteile

Auf Systemen ohne (ordnungsgemäß) installierte JRE lässt sich die Anwendung nicht starten

Die Anwendung läuft nicht, wenn sie APIs verwendet, die in der Standard-JRE nicht vorhanden sind

Anwender müssen darauf aufmerksam gemacht werden, dass sich JAR-Dateien durch Klicken öffnen lassen

Ressourcen
JAR File Specification
Tools
One-JAR
Autojar
Fat Jar
Java-Launcher

Java Web Start (JWS) und das zugrunde liegende Java Network Launch Protocol (JNLP) ermöglichen die Bereitstellung von Java-Anwendungen über einen standardmäßigen Webserver. Der Endanwender initiiert die Installation der Anwendung durch Klicken auf eine URL. Ist auf dem System keine Java Web Start-Engine vorhanden, wird der Anwender aufgefordert, diese herunterzuladen und zu installieren. Nachdem dies geschehen ist, bewirkt ein erneutes Klicken auf die gleiche URL, dass die erforderlichen Download- und Installationsvorgänge für die Anwendung eingeleitet werden, wozu auch der Download und die Installation der benötigten JRE-Version und der optionalen Pakete gehören können. Nach erfolgreichem Abschluss dieser Vorgänge wird die Anwendung gestartet. Sie wird lokal im Cache auf dem Computer des Anwenders gespeichert. Wenn der Anwender das nächste Mal auf die gleiche URL klickt und die JWS-Engine feststellt, dass der Computer offline ist oder die Anwendung auf der Website nicht aktualisiert wurde, wird die lokale Kopie aus dem Cache gestartet.

Eine weitere wichtige Funktion von JWS ist die Möglichkeit, die Anwendung in einer Sandbox – einem auf der Java-Sicherheitsarchitektur basierenden abgeschotteten Container – auszuführen. Aber im Gegensatz zu einem Applet kann Ihre Anwendung – selbst wenn sie aus einer nicht vertrauenswürdigen Umgebung stammt – über die JNLP-API auf lokale Systemressourcen wie das Dateisystem, den Drucker und die Zwischenablage zugreifen, nachdem der Anwender zur Bestätigung aufgefordert wurde.

Java Web Start ist in der normalen Oracle JRE (nicht aber in der Server-Version) enthalten, mit Plugins für gängige Browser, obgleich einige Änderungen der Browserkonfiguration erforderlich sein können. Das Tool JavaFX Packager kann insbesondere JavaFX-Anwendungen für die Bereitstellung über Java Web Start vorbereiten. Zudem gibt es Drittanbieterimplementierungen des JNLP-Protokolls, von denen einige ebenfalls Tools enthalten, die Sie bei der Erstellung und Pflege von JNLP-Paketen unterstützen.

Soweit die guten Nachrichten. Nun, was ist nicht so toll an JNLP? Um einen nahtlosen Betrieb zu gewährleisten, muss sowohl der Browser als auch der Webserver, der als Host für die JNLP-aktivierte Anwendung fungiert, den MIME-Typ application/x-java-jnlp-file unterstützen. Diese Voraussetzung ist bei einigen Hosting-Providern nicht gegeben. Zudem stellen Versionierung und das Durchführung von inkrementellen Updates zusätzliche Anforderungen an den Webserver, der über Servlet-Funktionalität verfügen und CGI-BIN-Skripts usw. unterstützen muss.

Auf der Clientseite wird der Browser während der Installation der JWS-Engine so konfiguriert, dass er den oben erwähnten MIME-Typ erkennt. Anwender, die einen weniger gebräuchlichen Browser verwenden, wie beispielsweise Opera, müssen diese Konfiguration ggf. manuell vornehmen.

Für das JNLP-Deployment muss der Anwendungscode geringfügig angepasst werden und die Anwendung in JAR-Dateien gepackt werden.

Bis J2SE 5.0 hatte JWS im Hinblick auf die Desktop-Integration nur sehr wenig zu bieten – die diesbezüglichen Funktionen von JWS beschränkten sich darauf, ein Desktop-Symbol und/oder einen Startmenüeintrag für die Anwendung zu erstellen. Unter Windows wird die Anwendung nicht unter "Programme hinzufügen/entfernen" angezeigt, d. h. die Endanwender müssten den Java Web Start-Anwendungsmanager ausführen, um Ihre Anwendung zu entfernen.

Und auch die JWS-Benutzeroberfläche bedarf einer Überarbeitung: Anwender werden unter Umständen mit hässlichen Fenstern mit unverständlichen Fehlermeldungen konfrontiert.

Zusammenfassend lässt sich sagen, dass JWS in einer kontrollierten Umgebung, wie beispielsweise einem unternehmenseigenen Intranet, durchaus eine praktikable Lösung darstellen kann, aber für den Verbrauchermarkt eher nicht geeignet ist. Hier empfehlen sich

Java Web Start

Vorteile

Für alle gängigen Desktop-Plattformen verfügbar

Eine einzige Distribution für alle JWS-aktivierten Plattformen

Codesignatur und Sandkastenprinzip

Versionierung und inkrementelle Updates

Automatische Installation von JREs und optionalen Paketen

Optionale Verwendung von Drittanbietertools

Nachteile

Internetverbindung erforderlich, falls JWS, JRE, und/oder ein optionales Paket nicht auf dem System installiert sind

Der MIME-Typ JNLP muss sowohl vom Webserver als auch vom Browser unterstützt werden

Begrenzte Möglichkeiten zur Desktop-Integration

Ressourcen

Java Rich Internet Applications Guide

Deploying Software with JNLP and Java™ Web Start

Java Web Start
(Java-Glossar von Roedy Green)

Lopica - All Things Web Start
Tools
JavaFX Packager
Xito Application Manager
Automatic JNLP Generator

Wenn ein Java-Programm über eine der oben beschriebenen Methoden (Batchdatei, ausführbare JAR-Datei oder Java Web Start/JNLP) aufgerufen wird, führt das Betriebssystem einen Java-Launcher über die JRE aus. Die Windows-Version der JRE verfügt über separate Launcher für befehlszeilenbasierte Anwendungen und für Anwendungen, die auf einer grafischen Benutzeroberfläche (GUI, Graphical User Interface) basieren. Sie haben die Bezeichnung java.exe bzw. javaw.exe.

Folglich haben alle laufenden Java-Anwendungen die gleichen Taskleisten-/Alt-Tab-Symbole und werden im Windows Task-Manager entweder als java.exe oder als javaw.exe. angezeigt. Werden zwei oder mehr Java-Anwendungen ausgeführt, ist es nicht möglich, zwischen mehreren Instanzen des standardmäßigen Java-Launchers im Task-Manager zu unterscheiden.

In Wirklichkeit sind diese Launcher nicht mehr als kleine native Programme, die die Java Virtual Machine aus einer DLL/freigegebenen Bibliothek laden und dann Ihr Programm über die Invocation-API in die JVM einspeisen. Die API ist Bestandteil der Java Native Interface (JNI), d. h. sie ist standardisiert und außerdem recht simpel aufgebaut. Das macht es relativ einfach, einen eigenen Launcher mit einem eindeutigen Namen und einem eindeutigen Symbol zu schreiben, dessen Aufgabe es ist, eine geeignete JRE auf dem System des Endanwenders zu suchen (sofern Sie die JRE nicht mit Ihrer Anwendung bündeln), die JVM zu laden, zu initialisieren und Ihre Anwendung darauf auszuführen.

Wem die richtigen Tools, die Kenntnisse oder die Zeit fehlen, um einen benutzerdefinierten Launcher für seine Java-Anwendung selbst zu entwickeln, der kann auf eine große Auswahl an Java-Launcher-Generatoren von Drittanbietern zurückgreifen. Diese sind rechts im Abschnitt "Tools" aufgeführt. (Dieser Abschnitt muss am häufigsten aktualisiert werden — mir scheint, dass Java-Entwickler viel Spass daran haben, dieses spezielle Rad immer wieder neu zu erfinden.) Einige dieser Tools bieten Zusatzfunktionen, wie beispielsweise die sofortige Anzeige des Begrüßungsbildschirms, STDOUT- und STDERR-Umleitung sowie — als bemerkenswerteste Eigenschaft — Wrapping-Funktionalität.

Ein Java-Wrapper ist im Wesentlichen ein benutzerdefinierter Java-Launcher, der zusätzlich ein selbstextrahierendes Archiv ist, das alle Klassen, JAR- und Hilfsdateien der Anwendung enthält. Der Wrapper entpackt diese Dateien beim Starten der Anwendung und entfernt sie bei deren Beendigung. Auf diese Weise wird Ihre Anwendung als eine einzige ausführbare Datei verteilt.

Normalerweise sucht ein Wrapper beim Starten nach der JRE. Ist keine JRE vorhanden oder stimmt deren Version nicht mit den Kompatibilitätsanforderungen der Anwendung überein, sind einige Wrapper in der Lage, die JRE zu installieren (falls Sie sie beim Packen Ihrer Anwendung hinzugefügt haben) und/oder die erforderliche JRE-Version herunterzuladen und zu installieren.

Die ausgereiftesten Wrapper sind zudem in der Lage, Dateizuordnungen einzurichten und bei der ersten Ausführung Verknüpfungen zu erstellen. Aber wenn Sie etwas Komplexeres benötigen, wie beispielsweise Unterstützung für automatische Updates oder eine einheitliche plattformübergreifende Bereitstellung, dann sollten Sie sich Folgendes anschauen:

Launcher und Wrapper

Vorteile

JRE-Versionsprüfung

JRE-Download oder Bündelung

Eindeutiger Prozessname und eindeutiges Symbol

Keine Endanwenderschulung erforderlich

Nachteile

Plattformspezifisch

Keine oder nur sehr begrenzte Möglichkeiten zur Desktop-Integration

Ressourcen

JNI Specification and FAQ

Tools (Kostenpflichtig):

Jar2Exe
NativeJ
JExePack
Jlaunch

Tools (Kostenfrei):

JavaFX Packager NEU
Packr NEU
conyay NEU
AppBundler Ant Task NEU
JSmooth
Launch4j
jstart32
exeJ
Java Launcher

Wenn Sie lediglich eine private Kopie der JRE neben Ihrer Anwendung installieren und Verknüpfungen zur Ausführung Ihrer Anwendung mit der JRE erstellen möchten, können Sie einen beliebigen Setup-Generator verwenden. Ein Java-fähiges Tool bietet Ihnen jedoch die folgenden Vorteile:

  • JRE-Erkennung und –Download während der Installation
  • Generierung von nativen Launchern
  • Vom Anwender bearbeitbare JVM-Parameterdateien
  • STDERR- und STDOUT-Umleitung zum Speichern von Protokollen und Ausnahmestapelüberwachungen
  • Registrierung der Java-Anwendungen als Windows-Dienste und Unix-Dämonen

Dies ist die am breitesten gefächerte Kategorie, was die Preise und die Funktionen der Tools angeht. Die Unterschiede werden im Folgenden am Beispiel erläutert.

Windows-orientierte Tools, wie Advanced Installer for Java bieten Ihnen die Möglichkeit, MSI-Dateien (Windows Installer-Pakete) zu erstellen.

Multiplattform-Tools können native Installer für mehrere Plattformen wie Windows, Linux, Mac OS X sowie für RPMs und Tarballs generieren. install4j ist eines dieser Tools. Und noch einmal der Hinweis: Speziell für JavaFX-Anwendungen können Sie JavaFX Packager verwenden, mit dem Sie MSI-, DMG-, RPM- und DEB-Pakete erzeugen können.

Des Weiteren gibt es Java-basierte Setup-Authoring-Tools, mit denen Sie plattformübergreifende Installationen erstellen können. Bei diesen Installationen handelt es sich im Wesentlichen um ausführbare JAR-Dateien mit einer plattformspezifischen Logik, die zur Laufzeit ausgewählt wird. InstallAnywhere ist vielleicht das bekannteste Tool dieser Art. Falls dessen Preis Ihr Budget überschreitet, können Sie auch das mit eingeschränktem Funktionsumfang kostenfrei erhältliche Tool JWrapper in Betracht ziehen, das sowohl native als auch plattformübergreifende Installer erstellt. Alternativ können Sie auch auf das auf Open Source basierende Tool IzPack zurückgreifen.

Und schließlich gibt es noch den Alleskönner InstallShield. Mit ihm lassen sich sowohl MSI-basierte (Windows-Desktop) als auch plattformübergreifende Installationen für Server und mobile Geräte für alle Arten von Anwendungen sowie für eine Vielzahl von Plattformen erstellen. Zudem unterstützt das Tool die JRE-Suche und -Bündelung, native Launcher usw.

Für einfache Installationen ist InstallShield jedoch überdimensioniert. Beachten Sie bitte auch, dass InstallAnywhere und InstallShield für den Unternehmenseinsatz konzipiert wurden und dementsprechend teuer sind.

Das grundlegende Prinzip, das im ersten Abschnitt dieses Artikels beschrieben ist, bleibt bei allen der oben genannten Lösungen bestehen. Egal, ob Sie eine ausführbare JAR-Datei oder einen anspruchsvollen Installer erstellen möchten: Ihr Java-Programm wird weiterhin als plattformunabhängiger Bytecode bereitgestellt. In den Anfangszeiten von Java gab es nur eine Möglichkeit, ein Java-Programm auf einer gängigen PC-Hardwareplattform auszuführen. Diese bestand darin, den Bytecode zu interpretieren. Heute enthält jede vernünftige Java-Implementierung einen Just-In-Time-Compiler (JIT-Compiler), der häufig ausgeführte Methoden zur Laufzeit in nativen Code kompiliert. Was liegt näher, als noch einen Schritt weiter zu gehen und die gesamte Anwendung vor der Bereitstellung in nativen Code zu kompilieren? Solche Tools gibt es und sie heißen

Setup-Authoring-Tools

Vorteile

Vollständige Desktop-Integration

Können plattformspezifisch oder plattformübergreifend sein

Lokalisierungsunterstützung

Flexibilität

Nachteile

Erfordern Drittanbietertools, die möglicherweise zu kostspielig und/oder zu komplex sind

Ressourcen
AppDeploy.com
Tools (Kostenpflichtig):

Advanced Installer for Java
install4j
InstallAnywhere
InstallShield
JExpress
JWrapper

Tools (Kostenlos):

JavaFX Packager NEU
IzPack
jelude (NSIS Skript)

AOT-Compiler werden auch als "statische Compiler" oder "Native-Code-Compiler" bezeichnet. Letztere Bezeichnung ist am gebräuchlichsten und – wie so häufig – zumindest in technischer Hinsicht am unpassendsten, da JIT-Compiler ebenfalls nativen Code erzeugen.

Ein Ahead-Of-Time-Compiler (AOT-Compiler) erstellt aus Ihren JAR- und Klassendateien eine herkömmliche native ausführbare Datei für die Zielplattform, wie beispielsweise eine Windows EXE-Datei oder eine Linux ELF-Binärdatei. Wie bei jeder anderen technischen Lösung gibt es auch hier Vor- und Nachteile.

Vorteile

  • Leistung. Ein JIT-Compiler arbeitet zur Laufzeit der Anwendung und gibt CPU- und Speicherressourcen für die zu kompilierende Anwendung und eventuelle andere Anwendungen frei. Ein AOT-Compiler wird bereits auf dem System des Entwicklers ausgeführt, und zwar ohne Einschränkungen im Hinblick auf Ressourcen oder Kompilierungszeit. Ein AOT-Compiler kann daher leistungsstärkere und ressourcenintensive Optimierungsmöglichkeiten anwenden, sodass der Code verbessert wird.

    Dieser Vorteil potenziert sich, wenn Ihre Anwendung auf Embedded Systems oder leistungsschwachen Desktop-PCs bereitgestellt wird, deren Ressourcen für den Einsatz eines JIT-Compilers einfach nicht ausreichen.

  • Schutz geistigen Eigentums. Java-Bytecode lässt sich sehr einfach dekompilieren – Sie brauchen nur nach "Download Java Decompiler" zu googeln und innerhalb von 5 Minuten haben Sie Ihren Quellcode zurück. Natürlich können Sie die Namen der öffentlichen Klassen und Methoden verschleiern, auf die nicht per Reflection oder JNI zugegriffen wird, aber eine übermäßige Verschleierung der Ablaufsteuerung kann zur Folge haben, dass Ihr Bytecode auf künftigen JVMs nicht verifizierbar ist. Zudem werden durch die Verschleierung die Optimierungsmöglichkeiten des JIT-Compilers eingeschränkt. Und schließlich bringt eine Verschlüsselung Ihres Java-Bytecodes überhaupt nichts — egal, welchen Verschlüsselungsalgorithmus Sie verwenden.

    Der native Code, der von einem optimierenden AOT-Java-Compiler erzeugt wird, lässt sich hingegen fast genauso schwer zurückentwickeln wie C++ Programmcode. Natürlich gibt es auch keine Leistungsverluste. Falls Sie sich Sorgen um den Schutz Ihres geistigen Eigentums machen, sollten Sie sich einmal näher mit der nativen Kompilierung beschäftigen.

  • Bessere Usability. Java-Client-Anwendungen leiden häufig am sogenannten Warmlaufzyklussyndrom. Das Starten einer Java-Anwendung umfasst die Schritte Bytecode-Interpretierung, Profilerstellung und JIT-Kompilierung. Folglich entsteht der Eindruck, dass Java-Programme wesentlich mehr Zeit zum Starten benötigen als ihre nativen Gegenstücke. Auch ist die Reaktionszeit eines komplexen GUI-Elements, wie z. B. einer Tabellen- oder Baumansicht, beim ersten Laden deutlich schlechter als nach mehreren Ladevorgängen. Dies sind zwei der Hauptgründe, warum Java von vielen Anwendern nach wie vor als langsam empfunden wird.

    Eine native ausführbare Datei wird direkt auf der Hardware ausgeführt. Da die Schritte Interpretierung, Profilerstellung und Kompilierung entfallen, lässt sich die Applikation schneller starten und zeigt sofort beste Reaktionszeiten.

  • Natives Deployment. Auch die ausgereiftesten Java-fähigen Setup-Tools müssen native Launcher generieren, um die Desktop-Integration zu verbessern, und diese Launcher müssen möglicherweise ebenfalls die JRE herunterladen und installieren.

    Ausführbare Dateien, die von einem AOT-Java-Compiler erstellt wurden, sind nicht mehr von der JRE abhängig. Sie können unter Verwendung jedes beliebigen Setup-Authoring-Tools bereitgestellt werden, welches für die Zielplattform verfügbar ist. Außerdem gibt es AOT-Compiler mit speziell angepassten Setup-Generatoren, die kompakte, professionelle Installer erstellen.

Nachteile

  • Dynamische Anwendungen. Klassen, die von der Anwendung zur Laufzeit dynamisch geladen werden, stehen möglicherweise nicht zur Verfügung. Hierbei kann es sich um Plugins von Drittanbietern, dynamische Proxys und andere Klassen handeln, die zur Laufzeit generiert werden. Um diese Szenarien trotzdem zu unterstützen, muss das AOT-Laufzeitsystem zusätzlich einen Java-Bytecode-Interpreter und/oder einen JIT-Compiler enthalten.

    Außerdem können im Allgemeinen nur Klassen, die entweder vom System- oder vom Anwendungsklassenlader geladen werden, in nativen Code vorkompiliert werden. Anwendungen, die benutzerdefinierte Klassenlader verwenden, können nur zum Teil vorkompiliert werden, es sei denn, der AOT-Compiler und die Laufzeitumgebung kennen das Verhalten der jeweiligen Klassenlader. So können beispielsweise Eclipse RCP-Anwendungen vollständig kompiliert werden, obwohl die meisten Klassen von speziellen OSGi-Klassenladern geladen werden. Ferner ist es möglich, Web-Anwendungen zu kompilieren, die mit Apache Tomcat ausgeführt werden.

  • Hardwarespezifische Optimierungen. Ein JIT-Compiler bietet gegenüber AOT-Compilern insofern einen potenziellen Vorteil, als er zur Laufzeit Code generieren kann, der zur tatsächlichen Hardware des ausführenden Rechners passt. So kann er beispielsweise den neuesten SSE-Anweisungssatz verwenden, um Gleitkommaberechnungen zu beschleunigen, wenn der Prozessor diese Befehle unterstützt. Ein AOT-Compiler muss entweder Code für den kleinsten gemeinsamen Nenner erstellen oder mehrere Varianten der CPU-intensivsten Methoden erzeugen, was wiederum eine Erhöhung der Codegröße zur Folge hat.

Fehlannahmen

Java-Bytecode wurde ursprünglich für Kompaktheit konzipiert. Er ist wesentlich kompakter als ein typischer CPU-Anweisungssatz und benötigt weniger Speicherplatz als der entsprechende Maschinencode für einen Allzweckprozessor (z. B. Intel x86). Aber Java-Klassendateien enthalten nicht nur Code. Aufgrund der Entwicklung zahlreicher APIs hat die Menge an symbolischen Informationen in Java-Klassendateien im Laufe der Jahre deutlich zugenommen. Somit besteht heutzutage kein großer Unterschied mehr zwischen dem Speicherbedarf der Originalversion und dem Speicherbedarf der AOT-kompilierten Version einer Anwendung. Die Download-Größe der AOT-Version kann sogar kleiner sein als die Größe der JRE.

Auch besteht die häufige Fehlannahme, dass die AOT-Kompilierung zu Lasten der Java-Portabilität gehe. Dies ist zumindest insofern nicht der Fall, dass der Quellcode nicht geändert werden muss. Auf einer Plattform, für die Sie keinen AOT-Compiler haben, können Sie deshalb Ihre Anwendung immer als Bytecode bereitstellen (allerdings hat sich damit dann das Thema Schutz des geistigen Eigentums erledigt.)

Tools

Im Jahr 2000 war ein halbes Dutzend verschiedener AOT Java-Compiler auf dem Markt. Die einzigen, die heute noch übrig sind, sind Excelsior JET und GCJ (GNU Compiler for Java). Unten im Abschnitt "Bonusmaterial" finden Sie einen Vergleich dieser beiden Produkte.

Aktualisierung 7. Juli 2014: RoboVM ist ein interessantes neues Open-Source-Projekt, das es Ihnen ermöglicht, Java-Code in native ausführbare iOS-Dateien zu kompilieren. Allerdings verwendet es die Android-Standard-Bibliothek und nicht Java SE, sodass nur Portabilität zwischen iOS und Android gegeben ist.

Wenn Ihr Fokus auf Embedded Systems liegt, empfiehlt sich ein Blick auf Aonix PERC. Dieses Tool wurde für J2ME CDC konzipiert und bietet außerdem eingeschränkte Unterstützung für J2SE 1.3.

Hiermit endet der Hauptteil des Artikels. Ich werde den Inhalt regelmäßig aktualisieren. Wenn Sie Anregungen und Kommentare haben oder URLs von Ressourcen/Tools kennen, die ich dem Artikel noch hinzufügen sollte, freue ich mich über Ihre E-Mail. (Leider spreche ich kein Deutsch. Bitte schreiben Sie mir deshalb in Englisch oder Russisch.)

Sie können mich auch gerne kontaktieren, wenn Sie Hilfe bei der Optimierung, beim Schutz und/oder bei der Bereitstellung Ihrer Java-Anwendungen benötigen.

AOT Compiler

Vorteile

Leistungssteigerung

Schutz geistigen Eigentums

Bessere User Experience

Natives Deployment

Nachteile

Eingeschränkte Anwendbarkeit

Fehlannahmen

Höherer Speicherbedarf

Portabilitätsverlust

Ressourcen

Improving Swing Performance: JIT vs AOT Compilation

Cracking Java byte-code encryption

Tools

Excelsior JET
GCJ
RoboVM (iOS) NEU
Aonix PERC

Haftungsausschluss: Ich arbeite für den Hersteller von Excelsior JET. Wenn Sie befürchten, dass es sich hier um dreiste Schleichwerbung handelt, überspringen Sie diesen Abschnitt.

Zielplattformen

Auf der offizielle Seite zum GCJ-Status sind 15 unterstützte Ziele (Stand: Juli 2014) aufgeführt, die von "nackten" ARM- und XScale-Systemen bis hin zu IBM s390x-Mainframes reichen. Allerdings werden einige der Ziele – darunter auch Windows – nicht vollständig unterstützt.

Excelsior JET unterstützt Windows und Linux auf 32‑ und 64‑Bit x86‑Systemen. Die 32‑Bit-Windows-Version ist seit 2000 auf dem Markt, die entsprechende Linux-Version kam 2004 hinzu, d. h. beide Versionen sind mittlerweile ziemlich ausgereift. Die erstmals 2013 veröffentlichten 64‑bit-Versionen holen auf.

Standard compliance

GCJ hat die offizielle JCK-Testreihe von Oracle (Java Compatibility Kit) nicht bestanden und ist weit davon entfernt, überhaupt einen entsprechenden Versuch zu starten. Der Hauptgrund ist, dass die GCJ-Laufzeitbibliothek libgcj eine auf Open Source basierende Reinraum-Implementierung der Core Java API-Klassen ist und somit selbst vor der Übernahme durch Oracle weit abgeschlagen hinter den Sun-Entwicklungen zurücklag. Derzeit kann GCJ nur wenige grafische Anwendungen kompilieren, die mit AWT-unabhängigen GUI-Toolkits von Drittanbietern (z. B. mit SWT) erstellt wurden.

libgcj verschmilzt langsam mit GNU Classpath. Laut der inoffiziellen Kompatibilitätstestergebnisse für GNUClasspath sollten im September 2007 (dem Zeitpunkt der letzten Testdurchführung) die meisten, aber nicht alle JDK 1.4 API-Funktionen vorhanden sein. Dabei ist jedoch zu beachten, dass die Daten, die diese Behauptung stützen sollen, nicht anhand der Tests aus dem JCK produziert wurden und somit lediglich die Verfügbarkeit, nicht aber die Kompatibilität der entsprechenden APIs bestätigen können.

Excelsior ist ein autorisierter Java-Lizenznehmer. Excelsior JET verwendet deshalb die lizenzierten Oracle-Implementierungen der Java SE-API. Excelsior JET hat die JCK-Tests bestanden und wurde auf einer Reihe von Windows- und Linux-Plattformen als Java SE 7 kompatibel zertifiziert. Java 8-Unterstützung ist zurzeit in Arbeit.

Update 23.07.2014: Excelsior JET 10 hat Java SE 7 JCK unter OS X bestanden.

Dynamisches Laden von Klassen

Beide Produkte unterstützen das dynamische Laden von Klassen. Die GCJ-Laufzeitumgebung führt dynamisch geladene Klassen auf einem Interpreter aus, während die Excelsior JET-Laufzeitumgebung über einen JIT-Compiler verfügt.

Bereitstellungsmöglichkeiten

GCJ ist ein reiner Compiler, d. h. Sie müssen sich um die Auswahl eines Drittanbieter-Bereitstellungstools und dessen Einrichtung zum Packen der erstellten ausführbaren GCJ-Dateien kümmern.

Excelsior JET enthält ein Toolkit, das Ihnen die Erstellung kompakter Windows- und Linux-Installer oder die einfache Einbindung von Setup-Generatoren von Drittanbietern ermöglicht. Außerdem besteht die Möglichkeit, Java-Anwendungen in Windows-Dienste zu kompilieren.

Preise

GCJ und libgcj sind Open-Source-Produkte (GPL) und können daher kostenlos heruntergeladen, modifiziert und verteilt werden. Hinweis: Die sog. libgcc exception gilt auch für libgcj. Daher fällt eine mit GCJ kompilierte Applikation nicht automatisch unter die GPL.

Excelsior JET-Lizenzen für die kommerzielle Nutzung sind ab 1.500 US-Dollar pro Entwickler erhältlich. Startups in der Frühphase und anderen sehr kleinen Unternehmen werden großzügige Rabatte angeboten.

Autoren von kostenlos herunterladbaren, nicht kommerziellen Java-Programmen können eine kostenfreie Lizenz anfordern.

Für die Ausführung auf Desktop-Computern und Servern fallen keine weiteren Kosten an. Nur wenn Sie Ihre Anwendung jedoch auf Embedded Systems bereitstellen oder wenn Sie sie mit Geräten bündeln, die dedizierte Funktionalität bereitstellen, werden Laufzeitgebühren fällig.

Andrew Fedoniouk hat mit seinem letzten Projekt namens J-SMILE mein Interesse geweckt. Ziel des Projekts ist die Erstellung von Java GUI-Anwendungen, die ohne JRE ausgeführt werden können. Im Wesentlichen handelte es sich dabei um eine Kombination aus der Waba VM und einer kleinen GUI-API, die zusammen mit den Klassendateien Ihrer Anwendung in eine weniger als 1 MB große ausführbare Datei gepackt werden können.

Wenn Sie andere interessante Versuche kennen, wie man die JRE loswerden kann, freue ich mich auf Ihre E-Mail. (Leider spreche ich kein Deutsch. Bitte schreiben Sie mir deshalb in Englisch oder Russisch.)

Hat Ihnen der Artikel gefallen? Wenn ja, haben wir noch mehr für Sie!

Weitere Artikel von Excelsior-Mitarbeitern: