Der Java Headless-Modus

1. Übersicht

Gelegentlich müssen wir mit grafikbasierten Anwendungen in Java arbeiten, ohne dass eine tatsächliche Anzeige, Tastatur oder Maus auf einem Server oder Container vorhanden ist.

In diesem kurzen Tutorial lernen wir den Headless-Modus von Java kennen, um dieses Szenario anzugehen. Wir werden uns auch ansehen, was wir im kopflosen Modus tun können und was nicht.

2. Einrichten des Headless-Modus

Es gibt viele Möglichkeiten, den Headless-Modus in Java explizit einzurichten:

  • Programmgesteuertes Setzen der Systemeigenschaft java.awt.headless auf true
  • Verwenden des Befehlszeilenarguments: java -Djava.awt.headless = true
  • Hinzufügen von -Djava.awt.headless = true zur Umgebungsvariablen JAVA_OPTS in einem Server- Startskript

Wenn die Umgebung tatsächlich kopflos ist, ist sich die JVM dies implizit bewusst. In einigen Szenarien gibt es jedoch geringfügige Unterschiede. Wir werden sie in Kürze sehen.

3. Beispiele für UI-Komponenten im Headless-Modus

Ein typischer Anwendungsfall für UI-Komponenten, die in einer kopflosen Umgebung ausgeführt werden, könnte eine Bildkonverter-App sein. Obwohl für die Bildverarbeitung Grafikdaten benötigt werden, ist eine Anzeige nicht unbedingt erforderlich. Die App kann auf einem Server ausgeführt und konvertierte Dateien gespeichert oder zur Anzeige über das Netzwerk an einen anderen Computer gesendet werden.

Lassen Sie uns dies in Aktion sehen.

Zuerst schalten wir den Headless-Modus programmgesteuert in einer JUnit- Klasse ein:

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

Um sicherzustellen, dass es korrekt eingerichtet ist, können wir java.awt.GraphicsEnvironment # isHeadless verwenden :

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

Wir sollten bedenken, dass der obige Test in einer kopflosen Umgebung erfolgreich ist, auch wenn der Modus nicht explizit aktiviert ist.

Nun sehen wir uns unseren einfachen Bildkonverter an:

@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 diesem nächsten Beispiel sehen wir, dass uns auch Informationen zu allen Schriftarten, einschließlich Schriftmetriken, zur Verfügung stehen:

@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

Es gibt Komponenten, die Peripheriegeräte erfordern und im Headless-Modus nicht funktionieren. Sie lösen eine HeadlessException aus, wenn sie in einer nicht interaktiven Umgebung verwendet werden:

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)

Dieser Test bestätigt, dass die Verwendung von Frame in einem Headless-Modus tatsächlich eine HeadlessException auslöst :

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

Denken Sie als Faustregel daran, dass Komponenten der obersten Ebene wie Frame und Button immer eine interaktive Umgebung benötigen und diese Ausnahme auslösen. Allerdings wird es als uneinbringlich geworfen werden Fehler , wenn der Headless Modus nicht explizit festgelegt wird .

5. Umgehen schwerer Komponenten im kopflosen Modus

An diesem Punkt stellen wir uns möglicherweise eine Frage - aber was ist, wenn wir Code mit GUI-Komponenten haben, die in beiden Arten von Umgebungen ausgeführt werden können - eine Produktionsmaschine mit Kopf und einen Server für die Quellcode-Analyse ohne Kopf?

In den obigen Beispielen haben wir gesehen, dass die Schwergewichtskomponenten auf dem Server nicht funktionieren und eine Ausnahme auslösen.

Wir können also einen bedingten Ansatz verwenden:

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

Mit diesem Muster können wir eine flexible App erstellen, die ihr Verhalten an die Umgebung anpasst.

6. Fazit

Mit verschiedenen Codebeispielen haben wir das Wie und Warum des Headless-Modus in Java gesehen. Dieser technische Artikel enthält eine vollständige Liste aller Funktionen im Headless-Modus.

Wie üblich ist der Quellcode für die obigen Beispiele auf GitHub verfügbar.