[Java/오류노트] Solved - Handler dispatch failed: java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11FontManager
adjh54
2025. 2. 27. 18:47
728x170
해당 글에서는 Docker 기반의 Could not initialize class sun.awt.X11FontManager 문제에 대한 해결 방법에 대해 작성한 글입니다.
1) 문제점
💡 문제점
- 엑셀 다운로드 기능을 Apachce POI 라이브러리를 이용하여서 구현하였고 이를 실행하였을때 로컬에서는 정상적으로 다운로드가 되었지만, 해당 코드를 Docker 기반 개발서버로 올렸을 경우 아래와 같은 오류가 발생하였습니다.
- Exception jakarta.servlet.ServletException: Handler dispatch failed: java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11FontManagerjava.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11FontManager
- java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11FontManager
- 해당 오류에서는 Apache POI를 사용하여 엑셀 파일을 생성하는 과정에서 ‘X11FontManager’ 클래스를 불러오지 못하는 문제였습니다. 이는 Apache POI는 내부적으로 AWT를 사용하여 엑셀 파일의 폰트나 색상 처리를 위해 AWT 관련 클래스를 호출합니다. - 해당 클래스의 경우는 GUI 그래픽 사용자 인터페이스를 사용하는데 이용됩니다. 그렇기에 GUI를 사용하지 않는 헤드리스 서버 환경을 설정해야 이를 이용할 수 있습니다.
- Java의 GUI(그래픽 사용자 인터페이스) 프로그래밍을 위한 최초의 라이브러리입니다. Java SE 플랫폼의 일부로, 윈도우, 버튼, 텍스트 필드 등과 같은 GUI 컴포넌트를 구현하는 데 사용됩니다. - Apache POI와 같은 라이브러리가 내부적으로 AWT를 사용하는 경우가 많은데, 특히 엑셀 파일 생성 시 폰트나 색상 처리를 위해 AWT 관련 클래스를 호출합니다.
💡 헤드리스 모드(Headless Mode)
- 그래픽 디스플레이(모니터)가 없는 환경에서 그래픽 기반의 작업을 수행할 수 있게 해주는 기능입니다. - 서버 환경에서는 일반적으로 GUI가 없기 때문에, AWT나 Swing과 같은 Java의 GUI 컴포넌트를 사용하는 작업을 수행하려면 헤드리스 모드를 활성화해야 합니다. - 헤드리스 모드가 활성화되면, 시스템은 실제 디스플레이 장치가 없어도 가상의 프레임버퍼를 사용하여 그래픽 작업을 수행합니다. 주로 서버 환경에서 이미지 처리, PDF 생성, 엑셀 파일 생성 등과 같은 작업을 할 때 필요합니다.
1. 헤드리스 모드 적용
💡 헤드리스 모드 적용 - 해당 헤드리스 모드를 적용하면 GUI가 없는 서버 환경에서도 엑셀 다운로드 같은 기능이 정상적으로 작동할 수 있습니다
- System Properties를 애플리케이션 코드 내에 포함하는 방법과 Docker를 이용하는 경우 Docker 내에 환경 변수를 추가하는 방법입니다. 이 두 방법을 동시에 적용할 필요는 없고 상황에 따라 적용하시면 됩니다.
- 첫 번째 방법으로 xxApplication.java 파일 내에 System.setProperty를 통해서 Java 시스템 속성을 설정하였습니다. - 해당 속성으로 헤드리스 모드를 활성화하는 값으로 지정하였습니다.
package com.blog.springbootexcelpoi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplicationpublicclassSpringBootExcelPoiApplication{
publicstaticvoidmain(String[] args){
// 애플리케이션 시작 전에 headless 모드 설정
System.setProperty("java.awt.headless", "true");
SpringApplication.run(SpringBootExcelPoiApplication.class, args);
}
}
1.2. Docker 파일 내에 환경 변수로 적용 방법 -2
💡 Docker 파일 내에 환경 변수로 적용 방법 -2
- 두 번째 방법으로 Docker 파일 내에 환경 변수로 적용하는 방법은 Dockerfile에 Java 애플리케이션을 실행하는 명령어에 직접 JVM 옵션을 추가하는 방식입니다. - 아래의 예시에서는 ENTRYPOINT 명령어를 사용하여 컨테이너가 시작될 때 실행될 명령어를 지정하였습니다.
FROM openjdk:17-jdk-alpine
// ...
ENTRYPOINT ["java", "-Djava.awt.headless=true", "-jar", "./app.jar"]
2. Docker 이미지 확인
💡 Docker 이미지 확인
- 위에 내용을 적용하였는데도 수행하지 않았을 때, 특정 글을 착안하여서 Docker 이미지를 변경하는 작업을 수행하였습니다.
- 기존의 openjdk:17-jdk-alpine 버전을 사용하고 있었는데, 경량화 버전이기에 일부 지원을 하지 않는다는 문제점을 파악하였고 openjdk:17-jdk 버전으로 변경하여 최종적으로 해결하였습니다.
💡 추후 개선 포인트 - alpine 버전을 사용하다가 일반 버전을 사용하는 경우 이미지 크기도 커지며, 비용문제도 발생할 수 있기에 이에 대한 변경을 추후 필요하였습니다. - 그렇기에 alpine 이미지 버전에 필요한 라이브러리를 추가하는 방법을 생각해보아야 할 것 같습니다.