使用documents4j转DOCX为PDF在Windows Server 2019中线程阻塞问题
DOCX转PDF服务在Windows Server 2019上的线程阻塞问题
我使用documents4j(内部通过VBScript实现转换)将DOCX文件转为PDF,代码取自documents4j官方实现。该代码作为Web服务部署在以Windows服务运行的Tomcat 9.0.37中,已创建C:\Windows\SysWOW64\config\systemprofile\Desktop文件夹,且安装了正版MS Office 2016。相同配置下,Windows Server 2012虚拟机可正常转换,但Windows Server 2019虚拟机中调用execute方法时线程永久阻塞,引发内存泄漏,栈跟踪如下:
org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [appName] is still processing a request that has yet to finish. This is very likely to create a memory leak. You can control the time allowed for requests to finish by using the unloadDelay attribute of the standard Context implementation. Stack trace of request processing thread:[ java.base@11.0.5/jdk.internal.misc.Unsafe.park(Native Method) java.base@11.0.5/java.util.concurrent.locks.LockSupport.park(LockSupport.java:194) java.base@11.0.5/java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:885) java.base@11.0.5/java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1039) java.base@11.0.5/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1345) java.base@11.0.5/java.util.concurrent.CountDownLatch.await(CountDownLatch.java:232) com.documents4j.job.AbstractFutureWrappingPriorityFuture.get(AbstractFutureWrappingPriorityFuture.java:204) com.documents4j.job.AbstractFutureWrappingPriorityFuture.get(AbstractFutureWrappingPriorityFuture.java:10) com.documents4j.job.ConversionJobAdapter.execute(ConversionJobAdapter.java:13)
代码片段1
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import com.documents4j.api.DocumentType; import com.documents4j.api.IConverter; import com.documents4j.job.LocalConverter; public class WordMLToPDF2 { public static void main(String[] args) { File inputWord = new File("C:\\Users\\anshu\\Downloads\\test.docx") , outputFile = new File("C:\\Users\\anshu\\Downloads\\test.pdf"); try { InputStream docxInputStream = new FileInputStream(inputWord); OutputStream outputStream = new FileOutputStream(outputFile); IConverter converter = LocalConverter.builder() .baseFolder(tmpDir) .workerPool(20, 25, 2, TimeUnit.SECONDS) .processTimeout(30, TimeUnit.SECONDS) .build(); converter.convert(docxInputStream).as(DocumentType.DOCX).to(outputStream).as(DocumentType.PDF).execute(); outputStream.close(); System.out.println("success"); converter.shutDown(); } catch (Exception e) { e.printStackTrace(); } } }
pom.xml依赖配置
<dependencies> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-documents4j-local</artifactId> <version>8.3.3</version> </dependency> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-JAXB-ReferenceImpl</artifactId> <version>8.3.3</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.17.1</version> </dependency> <!-- API, java.xml.bind module --> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>2.3.2</version> </dependency> <!-- Runtime, com.sun.xml.bind module --> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.3.2</version> </dependency> </dependencies>
分析结果
通过分析源码得知,documents4j借助zt-exec(ZeroTurnaround Process Executor)库执行VBScript来启动WINWORD、执行DOCX转PDF或关闭WINWORD;当执行wordApplication.Documents.Open(inputFile, False, True, False)时,WINWORD程序发生冻结,其中wordApplication为Word.Application对象。
内容的提问来源于stack exchange,提问作者Anshu
相关产品推荐
相关产品推荐

