Java AWT/Swing/JFreeChart/iText 等圖形操作默認依賴 X11 顯示服務。Linux 服務器通常無桌面環境 (Headless),導致 java.awt.headless=true 未設置時拋出 HeadlessException 或 Can't connect to X11 window server。本文解析根因並提供三大解決方案及容器化最佳實踐。
| 部署模式 | 配置位置 |
| 命令行直啟 | java -Djava.awt.headless=true -jar app.jar |
| Systemd 服務 | Environment="JAVA_OPTS=-Djava.awt.headless=true" |
| Tomcat | bin/setenv.sh: CATALINA_OPTS="$CATALINA_OPTS -Djava.awt.headless=true" |
| Jetty | start.ini: -Djava.awt.headless=true |
| Spring Boot | application.yml: spring.main.java-opts: -Djava.awt.headless=true |
| Docker | ENV JAVA_OPTS="-Djava.awt.headless=true" |
| Kubernetes | env: - name: JAVA_OPTS value: "-Djava.awt.headless=true" |
方案二:安裝虛擬幀緩衝 X Server (Xvfb)
# 安裝
apt-get install xvfb # Debian/Ubuntu
yum install xorg-x11-server-Xvfb # RHEL/CentOS
# 啟動虛擬顯示器 :99
Xvfb :99 -screen 0 1024x768x24 &
export DISPLAY=:99
# 或使用 xvfb-run 包裝器
xvfb-run -a java -jar app.jar
適用場景:需真實 X11 功能的場景 (Selenium 測試、特定字體渲染、舊版 JasperReports)。
方案三:使用 Pure Java 圖形庫繞過 AWT (PJA / Java2D 純軟件實現)
# Maven 依賴
<dependency>
<groupId>com.github.librepdf</groupId>
<artifactId>openpdf</artifactId>
<version>1.3.38</version>
</dependency>
# 或 PJA (較老)
<dependency>
<groupId>com.github.vedeshkin</groupId>
<artifactId>pja</artifactId>
<version>3.0</version>
</dependency>
# 系統屬性指向 PJA
-Djava.awt.graphicsenv=com.vedeshkin.awt.PJAGraphicsEnvironment
現代替代:OpenPDF (iText 5 分支)、Apache PDFBox、TwelveMonkeys ImageIO、Thumbnailator 等純 Java 圖形庫,無需 AWT 原生依賴,原生支援 Headless。
Tomcat 具體配置示例 (catalina.sh 修改)
# bin/setenv.sh (推薦,不修改 catalina.sh)
CATALINA_OPTS="$CATALINA_OPTS -Djava.awt.headless=true -Dfile.encoding=UTF-8"
# 若必須修改 catalina.sh (不推薦,升級覆蓋)
# 找到 org.apache.catalina.startup.Bootstrap 行,在前面插入
-Djava.awt.headless=true \
驗證方案生效
# 簡單測試類
public class HeadlessTest {
public static void main(String[] args) {
System.out.println("headless=" + System.getProperty("java.awt.headless"));
System.out.println("GraphicsEnv=" + GraphicsEnvironment.getLocalGraphicsEnvironment().getClass().getName());
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
g.drawString("Test", 10, 50);
g.dispose();
ImageIO.write(img, "png", new File("/tmp/test.png"));
System.out.println("Image written successfully");
}
}
# 編譯運行
javac HeadlessTest.java
java -Djava.awt.headless=true HeadlessTest
字體缺失導致輸出亂碼/方塊字追加方案
# 安裝開源字體
apt-get install fonts-dejavu-core fonts-liberation2 fonts-noto-cjk # Debian/Ubuntu
yum install dejavu-sans-fonts liberation-fonts google-noto-cjk-fonts # RHEL/CentOS
# 註冊字體目錄 (JDK 9+ 模塊化需額外)
# -Djava.awt.fontconfig.properties=...
決策樹:純服務端圖形處理 → -Djava.awt.headless=true (首選);需 Selenium/瀏覽器自動化 → Xvfb + Chrome/Firefox Headless;PDF/報表生成 → 遷移至 OpenPDF/PDFBox/Apache POI 純 Java 庫。徹底擺脫 X11 依賴,才是雲原生 Java 服務的正確姿態。