PdfConverter首次转换缓慢原因及Spring Boot优雅初始化方案咨询
Word转PDF首次转换速度过慢问题排查与优化咨询
我使用PdfConverter实现Word转PDF功能时,发现首次转换速度极慢,后续转换则明显加快。Spring Boot应用中该接口响应时间大致为12s→300ms→300ms。推测PdfConverter存在缓存机制,但未找到相关逻辑,耗时差异主要出现在PdfConverter#doConvert→XWPFDocumentVisitor#visitor() visitBodyElements环节。
复现代码
PdfOptions options = PdfOptions.create(); XWPFDocument xwpfDocument; String resourceLocation = "classpath:template/cadreTemplate-new.docx"; File template = ResourceUtils.getFile(resourceLocation); try (FileInputStream inputStream = new FileInputStream(template)) { xwpfDocument = new XWPFDocument(inputStream); } PdfConverter.getInstance().convert(xwpfDocument, new ByteArrayOutputStream(), options);
Maven依赖
<dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.poi.xwpf.converter.pdf-gae</artifactId> <version>2.0.3</version> </dependency>
咨询问题
- 不同的Word模板是否需要每次都初始化,还是只需初始化一次?
- 如何在Spring中以优雅的方式初始化
PdfConverter,以缩短首次请求的响应时间?
我已尝试多种方式排查响应时间差异问题。
问题解答
关于模板初始化的问题
- 不同的Word模板需要各自初始化:每个模板的结构、样式、内容都存在差异,
XWPFDocument是绑定具体模板的实例,无法跨模板复用。但如果是同一模板的多次转换,可缓存XWPFDocument实例(需注意线程安全,若模板内容无动态修改需求,可全局缓存)。
Spring中优化首次响应时间的方案
1. 启动时预热初始化
利用Spring的ApplicationRunner或CommandLineRunner,在项目启动阶段执行一次轻量转换操作,触发PdfConverter内部的类加载、资源初始化等耗时逻辑:
@Component public class PdfConverterWarmer implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { // 使用轻量测试模板完成首次初始化 String testTemplatePath = "classpath:template/test-empty.docx"; File testTemplate = ResourceUtils.getFile(testTemplatePath); try (FileInputStream inputStream = new FileInputStream(testTemplate)) { XWPFDocument doc = new XWPFDocument(inputStream); PdfConverter.getInstance().convert(doc, new ByteArrayOutputStream(), PdfOptions.create()); } } }
2. 复用PdfConverter单例实例
PdfConverter.getInstance()本身已是单例实现,确保整个应用中复用该实例即可,无需重复创建。
3. 固定模板缓存优化
对于频繁使用的固定模板,提前加载并缓存XWPFDocument实例(需保证模板文件不会被动态修改):
@Component public class TemplateCache { private final Map<String, XWPFDocument> templateCache = new ConcurrentHashMap<>(); @PostConstruct public void initCommonTemplates() throws Exception { // 预加载常用模板 loadTemplate("cadreTemplate", "classpath:template/cadreTemplate-new.docx"); } private void loadTemplate(String key, String path) throws Exception { File template = ResourceUtils.getFile(path); try (FileInputStream inputStream = new FileInputStream(template)) { templateCache.put(key, new XWPFDocument(inputStream)); } } public XWPFDocument getTemplate(String key) { return templateCache.get(key); } }
使用时直接从缓存获取模板实例,避免重复读取文件和初始化XWPFDocument的开销。
内容的提问来源于stack exchange,提问作者Smile
相关产品推荐
相关产品推荐

