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 이 발생합니다.

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에서 헤드리스 모드의 방법과 이유를 확인했습니다. 이 기술 문서 는 헤드리스 모드에서 작동하는 동안 수행할 수 있는 모든 작업의 ​​전체 List을 제공합니다.

평소와 같이 위 예제의 소스 코드는 GitHub에서 사용할 수 있습니다 .

Generic footer banner