1. 概要

場合によっては、で、実際のディスプレイ、キーボード、またはマウスを使用せずに、Javaでグラフィックベースのアプリケーションを操作する必要があります。たとえば、サーバーやコンテナで使用する必要があります。

この短いチュートリアルでは、このシナリオに対処するためのJavaのヘッドレスモードについて学習します。 また、ヘッドレスモードでできることとできないことについても見ていきます。

2. ヘッドレスモードの設定

Javaでヘッドレスモードを明示的に設定する方法はたくさんあります。

  • プログラムでシステムプロパティjava.awt.headlesstrueに設定します
  • コマンドライン引数の使用: java -Djava.awt.headless = true
  • サーバー起動スクリプトのJAVA_OPTS環境変数に-Djava.awt.headless=trueを追加する

環境が実際にヘッドレスである場合、JVMは暗黙的にそれを認識します。 ただし、一部のシナリオでは微妙な違いがあります。 間もなく表示されます。

3. ヘッドレスモードのUIコンポーネントの例

ヘッドレス環境で実行されるUIコンポーネントの一般的な使用例は、画像コンバーターアプリです。 画像処理にはグラフィックデータが必要ですが、表示は必要ありません。 アプリをサーバー上で実行し、変換されたファイルをネットワーク経由で別のマシンに保存または送信して表示することができます。

これを実際に見てみましょう。

まず、JUnitクラスでプログラムによってヘッドレスモードをオンにします。

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

正しく設定されていることを確認するために、 java.awt.GraphicsEnvironment isHeadlessを使用できます。

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

上記のテストは、モードが明示的にオンになっていない場合でも、ヘッドレス環境で成功することを覚えておく必要があります。

次に、単純な画像コンバーターを見てみましょう。

@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();
}

この次のサンプルでは、フォントメトリックを含むすべてのフォントの情報も利用できることがわかります。

@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

周辺機器を必要とし、ヘッドレスモードでは動作しないコンポーネントがあります。 非対話型環境で使用すると、HeadlessExceptionがスローされます。

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

このテストは、ヘッドレスモードで Frame を使用すると、実際にHeadlessExceptionがスローされることを示しています。

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

経験則として、FrameButtonなどのトップレベルのコンポーネントには常にインタラクティブな環境が必要であり、この例外がスローされることに注意してください。 ただし、ヘッドレスモードが明示的に設定されていない場合は回復不能エラーとしてスローされます

5. ヘッドレスモードでのヘビーウェイトコンポーネントのバイパス

この時点で、私たちは自分自身に疑問を投げかけるかもしれませんが、両方のタイプの環境(ヘッド付きの本番マシンとヘッドレスのソースコード分析サーバー)で実行するGUIコンポーネントを備えたコードがある場合はどうでしょうか。

上記の例では、重量のあるコンポーネントがサーバー上で機能せず、例外がスローされることを確認しました。

したがって、条件付きアプローチを使用できます。

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

このパターンを使用して、環境に応じて動作を調整する柔軟なアプリを作成できます。

6. 結論

さまざまなコードサンプルを使用して、Javaでのヘッドレスモードの方法と理由を確認しました。 この技術記事は、ヘッドレスモードで動作しているときに実行できるすべてのことの完全なリストを提供します。

いつものように、上記の例のソースコードは、GitHubから入手できます。