
Vor nicht allzu langer Zeit hat Oracle die erste Version des GraalVM-Projekts veröffentlicht (https://www.graalvm.org/). Der Veröffentlichung wurde sofort die Nummer 19.0.0 zugewiesen, anscheinend um zu überzeugen, dass das Projekt ausgereift und für den Einsatz in ernsthaften Anwendungen bereit ist. Einer der Teile dieses Projekts:
Substrate VM ist ein Framework, mit dem Sie Java-Anwendungen in native ausführbare Dateien umwandeln können (sowie native Bibliotheken, die in Anwendungen verbunden werden können, die beispielsweise in C / C ++ geschrieben sind). Diese Funktion wurde bisher als experimentell deklariert. Es ist auch erwähnenswert, dass native Java-Anwendungen einige Einschränkungen aufweisen: Sie müssen alle Ressourcen auflisten, die verwendet werden, um sie in das native Programm aufzunehmen. Sie müssen alle Klassen auflisten, die mit Reflektion und anderen Einschränkungen verwendet werden. Eine vollständige Liste finden Sie hier.
Native Image Java-Einschränkungen . Nach dem Studium dieser Liste ist es im Prinzip verständlich, dass die Einschränkungen nicht so bedeutend sind, dass es unmöglich war, komplexere Anwendungen als Höllenwörter zu entwickeln. Ich habe mir dieses Ziel gesetzt: Entwicklung eines kleinen Programms mit integriertem Webserver, Verwendung einer Datenbank (über die ORM-Bibliothek) und Kompilierung in eine native Binärdatei, die auf Systemen ohne installierten Java-Computer ausgeführt werden kann.
Ich werde mit Ubuntu 19.04 (Intel Core i3-6100 CPU bei 3,70 GHz × 4) experimentieren.
Installieren Sie GraalVM
Die GraalVM-Installation erfolgt bequem mit
SDKMAN . GraalVM-Installationsbefehl:
sdk install java 19.0.0-grl
OpenJDK GraalVM CE 19.0.0 wird installiert, CE ist Community Edition. Es gibt auch die Enterprise Edition (EE), diese Edition muss jedoch vom Oracle Technology Network
heruntergeladen werden. Der Link befindet sich auf der Seite
GraalVM-Downloads .
Nach der Installation von GraalVM, das bereits den Gu-Komponenten-Update-Manager von GraalVM verwendet, habe ich die Kompilierungsunterstützung in der nativen Binärdatei installiert.
gu install native-image
Alles, Arbeitswerkzeuge sind bereit, jetzt können Sie mit der Entwicklung von Anwendungen beginnen.
Einfache native Anwendung
Als Build-System verwende ich Maven. Um native Binärdateien zu erstellen, gibt es ein Maven-Plugin:
native-image-maven-plugin <build> <plugins> <plugin> <groupId>com.oracle.substratevm</groupId> <artifactId>native-image-maven-plugin</artifactId> <version>${graal.version}</version> <executions> <execution> <goals> <goal>native-image</goal> </goals> <phase>package</phase> </execution> </executions> <configuration> <imageName>nativej</imageName> <buildArgs> --no-server </buildArgs> </configuration> </plugin> </plugins> </build>
Es ist weiterhin erforderlich, die Hauptklasse der Anwendung festzulegen. Dies kann sowohl im Native-Image-Maven-Plugin als auch auf herkömmliche Weise über Folgendes erfolgen:
Maven-Jar-Plugin <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifest> <mainClass>nativej.Startup</mainClass> </manifest> </archive> </configuration> </plugin>
Erstellen Sie die Hauptklasse:
Startup.java public class Startup { public static void main(String[] args) { System.out.println("Hello world!"); } }
Jetzt können Sie den Befehl maven ausführen, um die Anwendung zu erstellen:
mvn clean package
Das Erstellen einer nativen Binärdatei auf meinem Computer dauert 35 Sekunden. Als Ergebnis wird eine Binärdatei mit einer Größe von 2,5 MB im Zielverzeichnis abgerufen. Das Programm benötigt keinen installierten Java-Computer und wird auf Computern ausgeführt, auf denen Java fehlt.
Repository-Link:
Github: native-java-helloworld-demo .
JDBC Postgres-Treiber
Und so funktioniert eine einfache Anwendung, die "Hallo Welt" anzeigt. Es wurden keine Lösungen benötigt. Ich werde versuchen, eine Ebene höher zu gehen: Ich werde den Postgres-JDBC-Treiber verbinden, um Daten aus der Datenbank anzufordern.
Bei Problemen mit dem GraalVM-Github treten Fehler im Zusammenhang mit dem Postgres-Treiber auf, jedoch mit GraalVM-Release-Kandidaten. Alle von ihnen sind als fest markiert.
Ich verbinde die postgresql-Abhängigkeit:
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.5</version> </dependency>
Ich schreibe den Code zum Extrahieren von Daten aus der Datenbank (die einfachste Benutzerplatte wurde erstellt):
Startup.java public class Startup { public static void main(String[] args) SQLException { final PGSimpleDataSource ds = new PGSimpleDataSource(); ds.setUrl("jdbc:postgresql://localhost/demo_nativem"); ds.setUser("test"); ds.setPassword("test"); try ( Connection conn = ds.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM \"public\".\"user\""); ) { while(rs.next()){ System.out.print("ID: " + rs.getLong("id")); System.out.println(", Name: " + rs.getString("name")); } } } }
Ich sammle die native Binärdatei und erhalte sofort einen Build-Fehler:
Error: No instances are allowed in the image heap for a class that is initialized or reinitialized at image runtime: org.postgresql.Driver. Try marking this class for build-time initialization with --initialize-at-build-time=org.postgresql.Driver
Tatsache ist, dass der native Anwendungs-Builder alle statischen Felder während des Erstellungsprozesses initialisiert (sofern nicht anders angegeben) und dies durch Untersuchen der Abhängigkeiten von Klassen tut. Mein Code bezieht sich nicht auf org.postgresql.Driver, sodass der Collector nicht weiß, wie er besser initialisiert werden kann (beim Erstellen oder beim Starten der Anwendung), und bietet an, ihn beim Erstellen für die Initialisierung zu registrieren. Dies kann durch Hinzufügen zu den Maven-Argumenten des Native-Image-Maven-Plugin-Plugins erfolgen, wie in der Fehlerbeschreibung angegeben. Nach dem Hinzufügen des Treibers wird der gleiche Fehler in Bezug auf org.postgresql.util.SharedTimer angezeigt. Wieder sammle ich einen solchen Build-Fehler und stoße darauf:
Error: Class initialization failed: org.postgresql.sspi.SSPIClient
Es gibt keine Empfehlungen zur Korrektur. Wenn man sich jedoch die Quelle der Klasse ansieht, ist klar, dass es sich um die Ausführung von Code unter Windows handelt. Unter Linux schlägt die Initialisierung (die während der Montage erfolgt) mit einem Fehler fehl. Es besteht die Möglichkeit, die Initialisierung zu Beginn der Anwendung zu verzögern: --initialize-at-run-time = org.postgresql.sspi.SSPIClient. Die Initialisierung unter Linux findet nicht statt und es werden keine Fehler mehr in Bezug auf diese Klasse angezeigt. Argumente erstellen:
<buildArgs> --no-server --no-fallback --initialize-at-build-time=org.postgresql.Driver --initialize-at-build-time=org.postgresql.util.SharedTimer --initialize-at-run-time=org.postgresql.sspi.SSPIClient </buildArgs>
Die Montage dauerte 1 Minute 20 Sekunden und die Datei schwoll auf 11 MB an. Ich habe ein zusätzliches Flag zum Erstellen der Binärdatei hinzugefügt: --no-fallback verbietet das Generieren einer nativen Binärdatei, für die eine installierte Java-Maschine erforderlich ist. Eine solche Binärdatei wird erstellt, wenn der Kollektor die Verwendung von Sprachfunktionen erkennt, die entweder in der Substrate-VM nicht unterstützt werden oder eine Konfiguration erfordern, aber noch keine Konfiguration vorhanden ist. In meinem Fall hat der Kollektor die mögliche Verwendung von Reflexion im JDBC-Treiber entdeckt. Dies ist jedoch nur eine mögliche Verwendung, es ist in meinem Programm nicht erforderlich, und daher ist keine zusätzliche Konfiguration erforderlich (wie dies gemacht wird, wird später gezeigt). Es gibt auch das Flag --static, das den Generator zwingt, libc statisch zu verknüpfen. Wenn Sie es jedoch verwenden, stürzt das Programm mit einem Segmentierungsfehler ab, wenn Sie versuchen, den Netzwerknamen in eine IP-Adresse aufzulösen. Ich habe nach Lösungen für dieses Problem gesucht, aber nichts Passendes gefunden, also habe ich die Programmabhängigkeit von libc verlassen.
Ich führe die resultierende Binärdatei aus und erhalte den folgenden Fehler:
Exception in thread "main" org.postgresql.util.PSQLException: Could not find a java cryptographic algorithm: TLS SSLContext not available.
Nach einigen Recherchen wurde die Fehlerursache identifiziert: Postgres stellt standardmäßig eine TLS-Verbindung mithilfe der elliptischen Kurve her. SubstrateVM beinhaltet nicht die Implementierung solcher Algorithmen für TLS. Hier ist das entsprechende offene Problem -
Single-Binary ECC (ECDSA / ECDHE) TLS-Unterstützung für SubstrateVM . Es gibt verschiedene Lösungen: Platzieren Sie die Bibliothek aus dem GraalVM-Paket: libsunec.so neben der Anwendung, konfigurieren Sie die Liste der Algorithmen auf dem Postgres-Server, schließen Sie Elliptic Curve-Algorithmen aus oder deaktivieren Sie einfach die TLS-Verbindung im Postgres-Treiber (diese Option wurde ausgewählt):
dataSource.setSslMode(SslMode.DISABLE.value);
Nachdem der Fehler beim Herstellen einer Verbindung mit Postgres behoben wurde, starte ich die native Anwendung, sie wird ausgeführt und zeigt Daten aus der Datenbank an.
Repository-Link:
Github: native-java-postgres-demo .
DI-Framework und eingebetteter Webserver
Bei der Entwicklung einer komplexen Java-Anwendung wird normalerweise ein Framework verwendet, z. B. Spring Boot. Nach diesem Artikel der
Unterstützung für native GraalVM-Images zu urteilen, wird
uns die Arbeit von Spring Boot im nativen Image "out of the box" nur in der Version von Spring Boot 5.3 versprochen.
Aber es gibt ein wunderbares
Micronaut- Framework, das
behauptet, im nativen GraalVM-Image zu funktionieren . Im Allgemeinen erfordert das Anschließen eines Micronaut an eine Anwendung, die in einer Binärdatei zusammengestellt wird, keine besonderen Einstellungen oder Problemlösungen. In Micronaut wurden bereits viele Einstellungen für die Verwendung von Reflection- und Verbindungsressourcen für die Substrate-VM vorgenommen. Übrigens können dieselben Einstellungen in Ihrer Anwendung in der Einstellungsdatei META-INF / native-image / $ {groupId} / $ {artefaktId} /native-image.properties platziert werden (ein solcher Pfad für die Einstellungsdatei wird von Substrate VM empfohlen) Dateiinhalt:
native-image.properties Args = \ -H:+ReportUnsupportedElementsAtRuntime \ -H:ResourceConfigurationResources=${.}/resource-config.json \ -H:ReflectionConfigurationResources=${.}/reflect-config.json \ -H:DynamicProxyConfigurationResources=${.}/proxy-config.json \ --initialize-at-build-time=org.postgresql.Driver \ --initialize-at-build-time=org.postgresql.util.SharedTimer \ --initialize-at-run-time=org.postgresql.sspi.SSPIClient
Die Dateien resource-config.json, Reflect-config.json, Proxy-config.json enthalten Einstellungen zum Verbinden von Ressourcen, Reflection und verwendeten Proxys (Proxy.newProxyInstance). Diese Dateien können manuell erstellt oder mit agentlib: native-image-agent abgerufen werden. Wenn Sie native-image-agent verwenden, müssen Sie das übliche jar (und nicht die native Binärdatei) mit dem Agenten ausführen:
java -agentlib:native-image-agent=config-output-dir=output -jar my.jar
Dabei ist die Ausgabe das Verzeichnis, in dem sich die oben beschriebenen Dateien befinden. In diesem Fall muss das Programm nicht nur ausgeführt werden, sondern auch Skripts im Programm ausführen, da Einstellungen in die Dateien geschrieben werden, wenn Sie Reflection verwenden, Ressourcen öffnen und einen Proxy erstellen. Diese Dateien können META-INF / native-image / $ {groupId} / $ {artefaktId} abgelegt und in native-image.properties referenziert werden.
Ich habe beschlossen, die Protokollierung mithilfe von Logback zu verbinden: Ich habe der logback-classic-Bibliothek und der Datei logback.xml eine Abhängigkeit hinzugefügt. Danach habe ich ein normales Glas kompiliert und es mit native-image-agent ausgeführt. Am Ende des Programms die notwendigen Einstellungsdateien. Wenn Sie sich deren Inhalt ansehen, können Sie sehen, dass der Agent die Verwendung von logback.xml zum Kompilieren in die Binärdatei registriert hat. Außerdem enthält die Datei Reflection-config.json alle Fälle der Verwendung von Reflection: Für bestimmte Klassen werden Metainformationen in die Binärdatei übertragen.
Dann habe ich der micronaut-http-server-netty-Bibliothek eine Abhängigkeit hinzugefügt, um den netty-basierten eingebetteten Webserver zu verwenden, und einen Controller erstellt:
Startup.java @Controller("/hello") public class HelloController { @Get("/{name}") @Produces(MediaType.TEXT_PLAIN) public HttpResponse<String> hello(String name) { return HttpResponse.ok("Hello " + name); } }
Und Hauptklasse:
HelloController.java public class Startup { public static void main(String[] args) { Signal.handle(new Signal("INT"), sig -> System.exit(0)); Micronaut.run(Startup.class, args); } }
Jetzt können Sie versuchen, eine native Binärdatei zu erstellen. Meine Montage dauerte 4 Minuten. Wenn Sie es ausführen und zur Adresse
http: // localhost: 8080 / hello / user gehen , tritt ein Fehler auf:
{"_links":{"self":{"href":"/hello/user","templated":false}},"message":"More than 1 route matched the incoming request. The following routes matched /hello/user: GET - /hello/user, GET - /hello/user"}
Ehrlich gesagt ist nicht ganz klar, warum dies passiert, aber nach der Suche durch Eingabe stellte ich fest, dass der Fehler verschwindet, wenn die folgenden Zeilen aus der Datei resource-config.json (die vom Agenten erstellt wurde) entfernt werden:
{"pattern":"META-INF/services/com.fasterxml.jackson.databind.Module"}, {"pattern":"META-INF/services/io.micronaut.context.env.PropertySourceLoader"}, {"pattern":"META-INF/services/io.micronaut.http.HttpResponseFactory"}, {"pattern":"META-INF/services/io.micronaut.inject.BeanConfiguration"}, {"pattern":"META-INF/services/io.micronaut.inject.BeanDefinitionReference"},
Micronaut registriert diese Ressourcen und es scheint, dass eine erneute Registrierung zu einer doppelten Registrierung meines Controllers und einem Fehler führt. Wenn Sie nach dem Korrigieren der Datei die Binärdatei neu erstellen und ausführen, treten keine Fehler mehr auf. Der Text „Hallo Benutzer“ wird unter
http: // localhost: 8080 / hello / user angezeigt.
Ich möchte auf die Verwendung der folgenden Zeile in der Hauptklasse aufmerksam machen:
Signal.handle(new Signal("INT"), sig -> System.exit(0));
Es muss eingesetzt werden, damit Micronaut korrekt fertig ist. Trotz der Tatsache, dass Micronaut einen Haken zum Herunterfahren aufhängt, funktioniert dies nicht in der nativen Binärdatei. Es gibt ein entsprechendes Problem:
Shutdownhook wird nicht mit Native ausgelöst . Es ist als fest markiert, hat jedoch nur eine Problemumgehung mit der Signal-Klasse.
Repository-Link:
Github: native-java-postgres-micronaut-demo .
ORM-Verbindung
JDBC ist gut, aber Reifen mit sich wiederholendem Code, endlosem SELECT und UPDATE. Ich werde versuchen, mein Leben zu erleichtern (oder zu erschweren, je nachdem, auf welche Seite ich schauen soll), indem ich eine Art ORM verbinde.
Ruhezustand
Zuerst habe ich mich für
Hibernate entschieden , da es eines der häufigsten ORMs für Java ist. Aufgrund eines Erstellungsfehlers konnte ich jedoch kein natives Image mit Hibernate erstellen:
Error: Field java.lang.reflect.Method.defaultValue is not present on type java.lang.reflect.Constructor. Error encountered while analysing java.lang.reflect.Method.getDefaultValue() Parsing context: parsing org.hibernate.annotations.common.annotationfactory.AnnotationProxy.getAnnotationValues(AnnotationProxy.java:63) parsing org.hibernate.annotations.common.annotationfactory.AnnotationProxy(AnnotationProxy.java:52) ...
Es gibt ein entsprechendes offenes Problem:
[native-image] Micronaut + Hibernate führt zu einem Fehler beim Analysieren von java.lang.reflect.Method.getDefaultValue () .
jOOQ
Dann habe ich beschlossen,
jOOQ zu versuchen. Ich habe es geschafft, eine native Binärdatei zu erstellen, obwohl ich viele Einstellungen vornehmen musste: Festlegen, welche Klassen initialisiert werden sollen (Buildtime, Runtime) und mit der Reflexion herumspielen. Am Ende kam es darauf an, dass jOOQ beim Start der Anwendung den Proxy org.jooq.impl.ParserImpl $ Ignore als statisches Mitglied der Klasse org.jooq.impl.Tools initialisiert. Und dieser Proxy verwendet MethodHandle, das Substrate VM
noch nicht unterstützt . Hier ist ein ähnliches offenes Problem:
[native-image] Micronaut + Kafka kann kein natives Image mit dem MethodHandle-Argument erstellen und konnte nicht auf höchstens einen einzigen Aufruf reduziert werden .
Apache Cayennepfeffer
Apache Cayenne ist weniger verbreitet, sieht aber recht funktionell aus. Ich werde versuchen, es zu verbinden. Ich habe XML-Dateien zur Beschreibung des Datenbankschemas erstellt. Sie können entweder manuell oder mit dem CayenneModeler-GUI-Tool oder basierend auf einer vorhandenen Datenbank erstellt werden. Mit dem Cayenne-Maven-Plugin in der POM-Datei wird die Codegenerierung von Klassen durchgeführt, die den Datenbanktabellen entsprechen:
Cayennepfeffer-Maven-Plugin <plugin> <groupId>org.apache.cayenne.plugins</groupId> <artifactId>cayenne-maven-plugin</artifactId> <version>${cayenne.version}</version> <configuration> <map>src/main/resources/db/datamap.map.xml</map> <destDir>${project.build.directory}/generated-sources/cayenne</destDir> </configuration> <executions> <execution> <goals> <goal>cgen</goal> </goals> </execution> </executions> </plugin>
Dann habe ich die CayenneRuntimeFactory-Klasse hinzugefügt, um die Datenbankkontextfactory zu initialisieren:
CayenneRuntimeFactory.java @Factory public class CayenneRuntimeFactory { private final DataSource dataSource; public CayenneRuntimeFactory(DataSource dataSource) { this.dataSource = dataSource; } @Bean @Singleton public ServerRuntime cayenneRuntime() { return ServerRuntime.builder() .dataSource(dataSource) .addConfig("db/cayenne-test.xml") .build(); } }
HelloController Controller:
HelloController.java @Controller("/hello") public class HelloController { private final ServerRuntime cayenneRuntime; public HelloController(ServerRuntime cayenneRuntime) { this.cayenneRuntime = cayenneRuntime; } @Get("/{name}") @Produces(MediaType.TEXT_PLAIN) public HttpResponse<String> hello(String name) { final ObjectContext context = cayenneRuntime.newContext(); final List<User> result = ObjectSelect.query(User.class).select(context); if (result.size() > 0) { result.get(0).setName(name); } context.commitChanges(); return HttpResponse.ok(result.stream() .map(x -> MessageFormat.format("{0}.{1}", x.getObjectId(), x.getName())) .collect(Collectors.joining(","))); } }
Anschließend startete er das Programm als reguläres JAR mit agentlib: native-image-agent, um Informationen über die verwendeten Ressourcen und die Reflexion zu sammeln.
Ich habe die native Binärdatei gesammelt, sie ausgeführt, gehe zur Adresse
http: // localhost: 8080 / hello / user und erhalte eine Fehlermeldung:
{"message":"Internal Server Error: Provider com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl not found"}
es stellt sich heraus, agentlib: native-image-agent hat die Verwendung dieser Klasse in der Reflexion nicht erkannt.
Manuelles Hinzufügen zur Datei Reflect-Config.json:
{ "name":"com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl", "allDeclaredConstructors":true }
Wieder sammle ich die Binärdatei, starte, aktualisiere die Webseite und erhalte einen weiteren Fehler:
Caused by: java.util.MissingResourceException: Resource bundle not found org.apache.cayenne.cayenne-strings. Register the resource bundle using the option -H:IncludeResourceBundles=org.apache.cayenne.cayenne-strings.
Hier ist alles klar, ich füge die Einstellung hinzu, wie in der vorgeschlagenen Lösung angegeben. Wieder sammle ich die Binärdatei (dies ist 5 Minuten Zeit), ich starte sie immer wieder ein Fehler, ein anderer:
No DataMap found, can't route query org.apache.cayenne.query.SelectQuery@2af96966[root=class name.voyachek.demos.nativemcp.db.User,name=]"}
Ich musste an diesem Fehler basteln, nach zahlreichen Tests, bei denen die Quellen untersucht wurden, wurde klar, dass der Grund für den Fehler in dieser Zeile aus der Klasse org.apache.cayenne.resource.URLResource liegt:
return new URLResource(new URL(url, relativePath));
Wie sich herausstellte, lädt Substrate VM die Ressource über die URL, die als Basis angegeben wird, und nicht über die URL, die auf der Basis von base und relativePath erstellt werden soll. Worüber das folgende Problem von mir registriert wurde:
Ungültiger Ressourceninhalt bei Verwendung einer neuen URL (URL-Kontext, Zeichenfolgenspezifikation) .
Der Fehler ist festgestellt. Jetzt müssen Sie nach Problemumgehungen suchen. Glücklicherweise erwies sich Apache Cayenne als eine ziemlich anpassbare Sache. Sie mussten Ihren eigenen Ressourcenlader registrieren:
ServerRuntime.builder() .dataSource(dataSource) .addConfig("db/cayenne-test.xml") .addModule(binder -> { binder.bind(ResourceLocator.class).to(ClassLoaderResourceLocatorFix.class); binder.bind(Key.get(ResourceLocator.class, Constants.SERVER_RESOURCE_LOCATOR)).to(ClassLoaderResourceLocatorFix.class); }) .build();
Hier ist sein Code:
ClassLoaderResourceLocatorFix.java public class ClassLoaderResourceLocatorFix implements ResourceLocator { private ClassLoaderManager classLoaderManager; public ClassLoaderResourceLocatorFix(@Inject ClassLoaderManager classLoaderManager) { this.classLoaderManager = classLoaderManager; } @Override public Collection<Resource> findResources(String name) { final Collection<Resource> resources = new ArrayList<>(3); final Enumeration<URL> urls; try { urls = classLoaderManager.getClassLoader(name).getResources(name); } catch (IOException e) { throw new ConfigurationException("Error getting resources for "); } while (urls.hasMoreElements()) { resources.add(new URLResourceFix(urls.nextElement())); } return resources; } private class URLResourceFix extends URLResource { URLResourceFix(URL url) { super(url); } @Override public Resource getRelativeResource(String relativePath) { try { String url = getURL().toString(); url = url.substring(0, url.lastIndexOf("/") + 1) + relativePath; return new URLResource(new URI(url).toURL()); } catch (MalformedURLException | URISyntaxException e) { throw new CayenneRuntimeException( "Error creating relative resource '%s' : '%s'", e, getURL(), relativePath); } } } }
Es hat eine Linie
return new URLResource(new URL(url, relativePath));
ersetzt durch:
String url = getURL().toString(); url = url.substring(0, url.lastIndexOf("/") + 1) + relativePath; return new URLResource(new URI(url).toURL());
Ich sammle die Binärdatei (70 MB), starte sie, gehe zu
http: // localhost: 8080 / hello / user und alles funktioniert, die Daten aus der Datenbank werden auf der Seite angezeigt.
Repository-Link:
Github: native-micronaut-cayenne-demo .
Schlussfolgerungen
Das Ziel wurde erreicht: Eine einfache Webanwendung mit Zugriff auf die Datenbank über ORM wurde entwickelt. Die Anwendung wird in eine native Binärdatei kompiliert und kann auf Systemen ohne installierte Java-Maschine ausgeführt werden. Trotz zahlreicher Probleme fand ich eine Kombination aus Frameworks, Einstellungen und Problemumgehungen, die es mir ermöglichten, ein Arbeitsprogramm zu erhalten.
Ja, die Möglichkeit, reguläre Binärdateien aus Java-Quellcode zu erstellen, befindet sich noch im experimentellen Status. Dies zeigt sich in der Fülle von Problemen und der Notwendigkeit, nach Problemumgehungen zu suchen. Am Ende stellte sich jedoch heraus, dass das gewünschte Ergebnis erzielt wurde. Was habe ich bekommen?
- Die einzige in sich geschlossene Datei (fast gibt es Abhängigkeiten von Bibliotheken wie libc), die auf Systemen ohne Java-Computer ausgeführt werden kann.
- Die Startzeit beträgt durchschnittlich 40 Millisekunden gegenüber 2 Sekunden beim Starten eines normalen Glases.
Unter den Mängeln möchte ich die lange Kompilierungszeit der nativen Binärdatei erwähnen. Ich brauche durchschnittlich fünf Minuten und werde höchstwahrscheinlich beim Schreiben von Code und beim Verbinden von Bibliotheken zunehmen. Daher ist es sinnvoll, Binärdateien basierend auf vollständig debuggtem Code zu erstellen. Darüber hinaus sind Debugging-Informationen für native Binärdateien nur in der kommerziellen Edition von Graal VM - Enterprise Edition verfügbar.