La modalità Java senza testa

1. Panoramica

A volte, dobbiamo lavorare con applicazioni basate su grafica in Java senza un display, una tastiera o un mouse effettivi, diciamo, su un server o un contenitore.

In questo breve tutorial, impareremo a conoscere la modalità headless di Java per affrontare questo scenario. Vedremo anche cosa possiamo fare in modalità senza testa e cosa non possiamo.

2. Impostazione della modalità senza testa

Ci sono molti modi in cui possiamo impostare esplicitamente la modalità headless in Java:

  • Impostazione programmatica della proprietà di sistema java.awt.headless su true
  • Utilizzando l'argomento della riga di comando: java -Djava.awt.headless = true
  • Aggiunta di -Djava.awt.headless = true alla variabile d'ambiente JAVA_OPTS in uno script di avvio del server

Se l'ambiente è effettivamente senza testa, la JVM ne sarebbe consapevole implicitamente. Tuttavia, ci saranno sottili differenze in alcuni scenari. Li vedremo a breve.

3. Esempi di componenti dell'interfaccia utente in modalità senza testa

Un tipico caso d'uso dei componenti dell'interfaccia utente in esecuzione in un ambiente headless potrebbe essere un'app di conversione di immagini. Sebbene abbia bisogno di dati grafici per l'elaborazione delle immagini, un display non è realmente necessario. L'app può essere eseguita su un server e file convertiti salvati o inviati in rete a un'altra macchina per la visualizzazione.

Vediamolo in azione.

Innanzitutto, attiveremo la modalità headless a livello di programmazione in una classe JUnit :

@Before public void setUpHeadlessMode() { System.setProperty("java.awt.headless", "true"); } 

Per assicurarci che sia impostato correttamente, possiamo usare java.awt.GraphicsEnvironment # isHeadless :

@Test public void whenSetUpSuccessful_thenHeadlessIsTrue() { assertThat(GraphicsEnvironment.isHeadless()).isTrue(); } 

Dobbiamo tenere a mente che il test di cui sopra avrà successo in un ambiente senza testa anche se la modalità non è esplicitamente attivata.

Ora vediamo il nostro semplice convertitore di immagini:

@Test public void whenHeadlessMode_thenImagesWork() { boolean result = false; try (InputStream inStream = HeadlessModeUnitTest.class.getResourceAsStream(IN_FILE); FileOutputStream outStream = new FileOutputStream(OUT_FILE)) { BufferedImage inputImage = ImageIO.read(inStream); result = ImageIO.write(inputImage, FORMAT, outStream); } assertThat(result).isTrue(); }

In questo prossimo esempio, possiamo vedere che sono disponibili anche le informazioni di tutti i caratteri, comprese le metriche dei caratteri:

@Test public void whenHeadless_thenFontsWork() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); String fonts[] = ge.getAvailableFontFamilyNames(); assertThat(fonts).isNotEmpty(); Font font = new Font(fonts[0], Font.BOLD, 14); FontMetrics fm = (new Canvas()).getFontMetrics(font); assertThat(fm.getHeight()).isGreaterThan(0); assertThat(fm.getAscent()).isGreaterThan(0); assertThat(fm.getDescent()).isGreaterThan(0); }

4. HeadlessException

Ci sono componenti che richiedono dispositivi periferici e non funzioneranno in modalità headless. Lanciano un'eccezione HeadlessException quando vengono utilizzati in un ambiente non interattivo:

Exception in thread "main" java.awt.HeadlessException at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204) at java.awt.Window.(Window.java:536) at java.awt.Frame.(Frame.java:420)

Questo test afferma che l'utilizzo di Frame in modalità headless genererà effettivamente un'eccezione HeadlessException :

@Test public void whenHeadlessmode_thenFrameThrowsHeadlessException() { assertThatExceptionOfType(HeadlessException.class).isThrownBy(() -> { Frame frame = new Frame(); frame.setVisible(true); frame.setSize(120, 120); }); } 

Come regola pratica, ricorda che i componenti di primo livello come Frame e Button necessitano sempre di un ambiente interattivo e genereranno questa eccezione. Tuttavia, verrà lanciato come errore irrecuperabile se la modalità headless non è impostata esplicitamente .

5. Bypassare i componenti pesanti in modalità senza testa

A questo punto, potremmo chiederci una domanda, ma cosa succederebbe se avessimo codice con componenti GUI da eseguire su entrambi i tipi di ambienti: una macchina di produzione headless e un server di analisi del codice sorgente headless?

Negli esempi precedenti, abbiamo visto che i componenti pesanti non funzioneranno sul server e genereranno un'eccezione.

Quindi, possiamo usare un approccio condizionale:

public void FlexibleApp() { if (GraphicsEnvironment.isHeadless()) { System.out.println("Hello World"); } else { JOptionPane.showMessageDialog(null, "Hello World"); } }

Usando questo modello, possiamo creare un'app flessibile che regola il suo comportamento in base all'ambiente.

6. Conclusione

Con diversi esempi di codice, abbiamo visto il come e il perché della modalità headless in java. Questo articolo tecnico fornisce un elenco completo di ciò che è possibile fare durante il funzionamento in modalità senza testa.

Come al solito, il codice sorgente per gli esempi precedenti è disponibile su GitHub.