OpenJDK Linux环境找不到“宋体”“微软雅黑”,因Java依赖fontconfig匹配字体家族名,而Windows字体的英文名(如"Microsoft YaHei")或中文名在Linux fontconfig中未注册;即使放入.ttf文件,若未正确配置别名、未执行fc-cache -fv或JVM未重启,Java仍不可见该字体。

为什么OpenJDK的Linux环境找不到“宋体”“微软雅黑”
Java调用Font构造器(如new Font("微软雅黑", ..., ...))时,不会直接读取.ttf文件,而是依赖系统级字体发现机制——即通过fontconfig扫描/usr/share/fonts/等目录,再匹配字体家族名(family name)。Windows字体的家族名(如"Microsoft YaHei")在Linux上根本不存在,哪怕你把msyh.ttf丢进系统,fc-list :family="Microsoft YaHei"也查不到。更常见的是:Java代码里写的是中文名"微软雅黑",但fontconfig只认英文名或别名,且默认不启用中文家族名映射。
直接在JRE内部放字体最省事(尤其Docker场景)
绕过系统字体查找,让Java自己加载字节流,这是生产环境最稳的做法。关键不是“装字体”,而是“让PDF库用上它”:
- 把
NotoSansCJKsc-Regular.ttf或SourceHanSansSC-Normal.otf放进src/main/resources/fonts/ - 用
BaseFont.createFont(..., BaseFont.IDENTITY_H, BaseFont.EMBEDDED)(iText)或PDType0Font.load(...)(PDFBox)显式加载 - 务必传
IDENTITY_H或COSName.IDENTITY_H,否则中文字符会被截断或映射错误 - 避免用
FontFactory.getFont("SimSun")这类依赖系统查找的封装——它在Linux上大概率返回默认拉丁字体
真要配系统字体,别碰/usr/share/fonts/根目录
往/usr/share/fonts/里扔文件+fc-cache -fv看似标准,但容易踩三个坑:
-
fc-cache需要mkfontscale和mkfontdir支持,Alpine镜像默认没装,Debian系得apt install fontconfig xfonts-utils - 上传的
simsun.ttc可能被fc-cache忽略——它只处理.ttf、.otf,不处理.ttc(TrueType Collection),得先用工具拆包或换用单文件字体 - Java进程启动后才读一次字体缓存,改完字体必须重启JVM,否则
GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()仍看不到新字体
验证字体是否真被Java识别,别只信fc-list :lang=zh
fc-list :lang=zh只说明fontconfig能列出中文字体,不代表Java能用。真正有效的检查方式是:
- 在应用里加一段调试代码:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); for (Font f : ge.getAllFonts()) { if (f.getFamily().contains("Noto") || f.getFamily().contains("Source")) { System.out.println("✅ Java可见: " + f.getFamily()); } } - 如果输出为空,说明字体没进Java的字体上下文——常见于字体放在
/usr/share/fonts/但没执行fc-cache -fv,或JVM启动早于字体安装 - 注意:OpenJDK 8u292+对字体加载有缓存,首次失败后即使补装字体,也可能继续走缓存路径,必须重启JVM
appuser)若无权读取/usr/share/fonts/custom/xxx.ttf,fc-list能看到,Java却加载失败——连错误日志都不抛,静默回退到默认字体。



















