Al momento stai visualizzando Superare Java 8: creare runtime Java personalizzati con jlink

Superare Java 8: creare runtime Java personalizzati con jlink

Secondo alcuni sondaggi come quello di JetBrains, la versione 8 di Java è al momento quella più utilizzata in assoluto dagli sviluppatori di tutto il mondo, nonostante si tratti di una release del 2014. Quello che state leggendo è un articolo che fa parte di una serie intitolata “Superare Java 8”, ispirata ai contenuti del mio ultimo libro “Il nuovo Java”. Questi articoli accompagneranno passo dopo passo il lettore all’esplorazione delle più importanti caratteristiche introdotte a partire dalla versione 9. L’obiettivo è quello di far acquisire la consapevolezza di quanto è importante aggiornare le proprie conoscenze relative a Java, spiegando gli enormi vantaggi che offrono le ultime versioni del linguaggio.

Prima di Java 9, per eseguire un’applicazione Java su una qualsiasi piattaforma era necessario che su di essa fosse installata il Java Runtime Environment. Oggi il classico JRE non esiste più, non è installato automaticamente quando si installa il JDK come in passato. Non esiste neanche più il Java Plugin che veniva installato nei browser per permettere l’esecuzione di applicazioni che usavano le storiche tecnologie Applet e Java Web Start (oramai non più utilizzabili). Oggi, per permettere l’esecuzione di un’applicazione Java su una particolare piattaforma, possiamo però creare un Java runtime personalizzato che contiene solo le librerie che servono al programma per essere eseguito, e distribuirlo come parte dell’applicazione stessa. Per fare ciò basta utilizzare il tool introdotto con il JDK 9 chiamato jlink, che si avvale dei vantaggi della modularizzazione del JDK.

 

Modularizzazione del JDK

Con la definizione del concetto di modulo, la versione 9 di Java ha portato con sé il refactoring modulare del JDK. Questo significa che ora i package della libreria standard di Java sono organizzati all’interno di moduli (anch’essi sono fisicamente delle semplici cartelle).

In particolare, il JDK nella versione 16 definisce 68 moduli, ma questo numero è destinato a cambiare (nella versione Java 9 ce n’erano 98 e con Java 15 erano scesi a 70). È possibile verificarlo eseguendo il comando:

java --list-modules

che stamperà la lista di tutti i moduli presenti nel JDK che riportiamo nella seguente tabella:

Figura 1 – Moduli del JDK 16.

Per esempio il modulo java.base, contiene i package fondamentali (base) come java.lang, java.io, java.math, java.time, java.util, java.util.stream e tanti altri.

 

Cosa possiamo fare ora

Prima della modularizzazione del JDK i nostri programmi dovevano sfruttare l’installazione completa del Java Runtime Environment sulla piattaforma di destinazione. Avevano quindi a disposizione tutte le librerie del JRE (come javafx.*java.sql.*, Applet) anche se non erano utilizzate. Tutte queste librerie erano incluse nel file rt.jar.

Con i moduli invece è possibile creare runtime personalizzati. Da Java 9 in poi infatti, possiamo distribuire i nostri programmi portandoci dietro solo le librerie necessarie. In questo modo si può ridurre la dimensione dell’applicazione e migliorarne le performance. Inoltre non sarà necessario un’installazione del JRE sulla macchina di destinazione, visto che creeremo un Java runtime personalizzato ed ottimizzato che distribuiremo insieme all’applicazione stessa.

 

Il tool jlink

Java 9 infatti ha introdotto un nuovo strumento chiamato jlink, un tool da riga di comando molto semplice da utilizzare. Esso ci permette di creare runtime personalizzati solo con i moduli che servono alla nostra applicazione. Per esempio, con il seguente comando creiamo un runtime contenente solo il modulo java.base:

jlink --add-modules java.base --output javabasert

Infatti con l’opzione --add-modules aggiungiamo il modulo java.base al runtime, mentre con l’opzione --output diamo il nome al runtime (javabasert).

A questo punto jlink creerà un runtime all’interno di una cartella che si chiama proprio javabasert, con tutta la struttura costituita dalle cartelle bin, lib, include, conf, legal.


Figura 2 – La struttura del runtime personalizzato javabasert, creato con jlink.

La dimensione del runtime javabasert che abbiamo creato non supera i 40 megabyte, mentre il JDK completo ha una dimensione di circa 290 megabyte. Possiamo anche comprimere al massimo il nostro runtime utilizzando anche l’opzione --compress 2 per ottenere una dimensione di circa 27 megabyte.

Con il seguente comando:

javabasert\bin\java --list-modules

possiamo stampare la lista dei moduli che il nuovo runtime definisce, ottenendo il seguente output:

java.base@16

che ci conferma che con javabasert possiamo sfruttare solo le librerie incluse nel modulo java.base della versione 16.

Se volessimo eseguire un’applicazione sfruttando il runtime appena creato, considerata la tipica classe HelloWorld:

public class HelloWorld {
    public static void main(String args[])   {
        System.out.print("Hello World!");
    }
}

basterà semplicemente utilizzare un comando come il seguente:

javabasert\bin\java HelloWorld

 

Dipendenze transitive tra moduli

Se vogliamo creare un runtime che includa anche il modulo java.desktop che contiene le librerie per creare interfacce grafiche, possiamo eseguire il comando:

jlink --add-modules java.base,java.desktop --output javabasedeskrt

dove abbiamo chiamato il nuovo runtime personalizzato javabasedeskrt.

Per verificare la corretta definizione dell’ambiente eseguiamo il comando:

javabasedeskrt\bin\java --list-modules

che produrrà il seguente output:

java.base@16
java.datatransfer@16
java.desktop@16
java.prefs@16
java.xml@16

In pratica, anche se pensavamo di aver aggiunto solo due moduli, in realtà ne ritroviamo anche altri. Questi perché i moduli sono legati da relazioni di dipendenza. In particolare, anche se abbiamo richiesto a jlink di aggiungere al nostro runtime solo i moduli java.base e java.desktop, quest’ultimo modulo ha delle dipendenze verso java.prefs, java.xml, java.datatransfer ed anche con java.base. Infatti, avremmo anche potuto evitare di specificare java.base tra i moduli da includere, avremmo ottenuto lo stesso risultato.

 

Il tool jdeps

Per poter capire come creare il giusto runtime, nel JDK 9 è stato rivisto il tool jdeps per visualizzare le dipendenze modulari. Anche in questo caso si tratta di un tool molto semplice da utilizzare. Per esempio, considerata la classe HelloWorld, il seguente comando:

jdeps HelloWorld.class

produrrà il seguente output:

HelloWorld.class -> java.base
<unnamed>                 -> java.io                java.base
<unnamed>                 -> java.lang              java.base

che ci mostra la dipendenza della classe HelloWorld dal modulo java.base, e siccome la nostra classe non appartiene ad un package, viene esplicitato che il package anonimo (unnamed) dipende dai package java.io e java.lang. Ovviamente, se la classe appartenesse al package mypackage, allora vedremmo mypackage al posto della stringa <unnamed>.

Il comando jdeps può prendere in input anche cartelle e file JAR oltre che classi.

Per visualizzare tutte le opzioni disponibili da usare sia col tool jlink che jdeps, è possibile utilizzare l’opzione --help.

 

Conclusioni

Indubbiamente il tool jlink rappresenta un passo in avanti verso il futuro per Java. Infatti fornendo pochissime informazioni possiamo creare runtime ottimizzati per la nostre applicazioni, rendendole più performanti, meno voluminose e più facili da distribuire. Il supporto del tool jdeps ci permette di capire quali moduli sono necessari nel runtime da creare per le nostre applicazioni. Inoltre entrambi i tool sono particolarmente semplici da utilizzare.

 

Note dell’autore

Anche ignorando la maggiore sicurezza che offrono le ultime versioni del JDK, esistono tantissimi motivi per aggiornare le proprie conoscenze di Java, o quantomeno le proprie installazioni del runtime di Java. Il mio ultimo libro “Il nuovo Java”, a cui si ispira la serie “Superare Java 8”, contiene tutte le informazioni per poter imparare Java da zero, ed utilizza un metodo didattico ben collaudato e perfezionato in 20 anni di esperienza, che rende l’apprendimento semplice e appassionante. Inoltre è strutturato per approfondire gli argomenti ed avere una conoscenza superiore che può fare la differenza per la vostra carriera lavorativa.

Questo articolo è ispirato principalmente ai paragrafi 16.5 e 16.6 del capitolo 16 del libro “Il nuovo Java”.

Per maggiori informazioni visitate https://www.nuovojava.it.

 

Questo articolo ha 4 commenti

  1. Antonio Flaccomio

    Questa e’ la prima caratteristica del “nuovo Java” che, se non ho frainteso qualcosa, mi lascia perplesso per almeno due motivi:
    – si perde definitivamente la portabilità di un’applicazione che ora deve essere distribuita in piu’ versioni (avendo a disposizione piu’ sistemi operativi);
    – se proprio era necessario perdere la portabilità si sarebbe almeno potuto costruire un eseguibile (un .exe nel caso di windows) per aiutare gli utenti meno smaliziati.

    Mi auguro che il primo punto possa essere almeno parzialmente risolto per esempio tramite un sito web che costruisca la jre a partire da un insieme di jar (e credo che oracle stesso potrebbe/dovrebbe farsene carico).

    1. cdesio

      Ciao Antonio! Scusami se ti rispondo con tutto questo ritardo ma ero in vacanza (sono appena tornato). Capisco le tue perpessità, ma non credo sia una cosa negativa poter distribuire varie versioni del tuo software senza obbligare l’host ad installare un JRE, anzi forse questo potrebbe favorire la diffusione delle applicazioni standalone scritte in Java. Tuttavia non sei obbligato a distribuire le applicazioni Java con un runtime personalizzato, puoi sempre affidarti ad un JRE presente sulla macchina host come si è sempre fatto, insomma non perdi la portabilità. Per quanto riguarda il secondo punto invece, nel frattempo che preparo un articolo in italiano sull’argomento (non semplice come JLink), puoi dare uno sguardo al nuovo strumento JPackage (https://docs.oracle.com/en/java/javase/14/jpackage/packaging-overview.html#GUID-C1027043-587D-418D-8188-EF8F44A4C06A), che fa esattamente quello ti aspetti.
      Ciao!

      1. Antonio Flaccomio

        Grazie, leggero’ con attenzione. A proposito, tu scrivi una serie di articoli molto interessante sul superamento di java8 mentre Oracle (https://www.java.com/it/download/) continua a proporre la jre 8 🙁

        1. cdesio

          Hai ragione… purtroppo la versione 8 è ancora la più usata, nonostante tra qualche giorno esca la versione 17! Ormai bisogna fare riferimento alla reference implementation che trovi (https://jdk.java.net), il jdk Oracle ormai è solo per chi ha bisogno di mantenere vecchie versioni usufruendo del supporto Oracle.

Lascia un commento