Linux 服务器导出报错修复记录:libfontmanager / libfreetype

工作笔记 工作记录
📅 2026-09-30 09:22 👤 admin

日期:2026-09-30

服务器:AWS Amazon Linux 2023(SRDAPP570001),JDK8 路径 /opt/jdk8,后端 systemd 部署

涉及模块:后端同步导出(ExcelUtil + POI 4.1.2 SXSSF)

一、现象

  1. 页面点导出,后端报:

    text
     
     
     
     
     
    Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError:
    /opt/jdk8/jre/lib/amd64/libfontmanager.so: libfreetype.so.6: cannot open shared object file
     
  2. 本地 Windows 环境同样操作完全正常,仅 Linux 服务器报错。

二、根因

  • 导出 Excel 时 POI(SXSSFWorkbook + createFont/setCellStyle + wb.write)会初始化 java.awt.Font → sun.font.FontManagerFactory → 加载 JDK 原生库 libfontmanager.so, 该库依赖系统库 libfreetype.so.6。 已在本机 JDK8 用 -verbose:class 实验复现确认:即使代码没有任何 AWT import、headless 模式下,纯 POI 写样式也会触发这条链。
  • Amazon Linux 2023 精简安装不带 freetype / fontconfig,导致 UnsatisfiedLinkError。
  • 该错误表现为 Handler dispatch failed 的原因:ExcelUtil.exportExcel 内是 catch (Exception e), 而 UnsatisfiedLinkError 是 Error 不是 Exception,接不住,直接穿透到 DispatcherServlet。

三、修复步骤(Amazon Linux 2023,yum/dnf)

bash
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
# 1. 安装核心库(freetype 解决本报错;fontconfig+字体避免下一阶段的 NPE)
sudo yum install -y freetype fontconfig dejavu-sans-fonts
 
# 2. 中文字体(会连带装 sans+serif ttc,约 300MB 磁盘)
sudo yum install -y google-noto-cjk-fonts
 
# 3. 刷新字体缓存
sudo fc-cache -f
 
# 4. 验证依赖已解析(关键看 libfreetype.so.6,见下方"踩坑"第 1 条)
ldd /opt/jdk8/jre/lib/amd64/libfontmanager.so | grep "not found"
ldd /opt/jdk8/jre/lib/amd64/libfontmanager.so | grep -Ei "freetype|fontconfig"
 
# 5. 重启后端服务(必做,原因见"踩坑"第 2 条)
sudo systemctl restart <服务名>
 

实际安装的包(2026-09-30 已执行成功): freetype-2.13.2-5、fontconfig-2.13.94-2、dejavu-sans-fonts-2.37-16、 google-noto-cjk-fonts-20230817-2(含 google-noto-sans/serif-cjk-ttc-fonts)。

四、踩坑记录

  1. ldd 显示 libjvm.so => not found 是正常现象,不要被吓到。libjvm.so 由 JVM 运行时自己 加载(在 jre/lib/amd64/server/ 下,不在系统库路径),所有 JDK 原生库用 ldd 看都是这样。 验证时只关注 libfreetype.so.6 是否还出现在 "not found" 列表里。

  2. 装完库必须重启服务。首次 UnsatisfiedLinkError 后,JVM 会把 sun.awt.X11FontManager 永久标记为"初始化失败",同一进程内不再重试,之后所有导出请求都会变成:

    text
     
     
     
     
    NoClassDefFoundError: Could not initialize class sun.awt.X11FontManager
     

    这是同一根因的第二阶段表现,不是修错了;重启即恢复。

  3. freetype 和 fontconfig/字体要一起装。只装 freetype,下一步常见 NullPointerException at sun.awt.FontConfiguration.getVersion。

  4. 应用若跑在 Docker 容器里,必须装进容器(镜像或 docker exec),宿主机 yum install 对容器内 JVM 无效。 本次部署为宿主机 systemd 直跑,无此问题。

  5. 无外网兜底方案:把任意 x86_64 Linux 上的 libfreetype.so.6 拷到 /opt/jdk8/jre/lib/amd64/ 下即可(JDK 优先从自己的 lib 目录找,无需配 LD_LIBRARY_PATH); 或恢复标准 JDK8 自带的 jre/lib/libfreetype.so(被裁剪过的 JDK 发行版可能缺失)。