PDFBOX增量签名时间歇性出现COSStream已关闭异常求助
PDFBox 增量签名间歇性抛出 COSStream 已关闭异常
问题描述
使用PDFBox执行PDF签名操作,调用saveIncrementalForExternalSigning方法前已添加验证信息,相关代码如下:
public ByteArrayOutputStream addSignature(PDDocument document, PDSignature signature, InputStream inputStream, SealCSCCredentialOptions cscCredentialOptions, Certificate[] certificateChain, String signatureFormat) throws Exception { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ExternalSigningSupport externalSigningSupport = null; try { externalSigningSupport = document.saveIncrementalForExternalSigning(outputStream); } catch (IOException e) { e.printStackTrace(); LOG.error("Request ID: {} Error occurred: " + e.getMessage(), LoggerUtils.getFromThreadContext("requestId")); throw e; } CMSSignedData signedData = generateCMSSignedData(certificateChain, externalSigningSupport, inputStream, cscCredentialOptions, signatureFormat); byte[] cmsSignature = signedData.getEncoded(); externalSigningSupport.setSignature(cmsSignature); return outputStream; }
但在调用externalSigningSupport = document.saveIncrementalForExternalSigning(outputStream);时,间歇性出现异常:COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed? 该错误并非每次出现,有时能成功返回结果。
排查方向与原因分析
1. PDDocument 实例的并发访问或重复使用问题
这个异常最常见的根源是同一个PDDocument实例被多个线程共享、重复调用关闭方法,或者在签名流程之外被意外关闭。由于问题是间歇性出现,大概率是存在线程安全问题:
- 如果该方法被多线程调用,且传入的是同一个
PDDocument实例,就可能出现一个线程还在操作流,另一个线程已经关闭了文档或流的情况。 - 检查调用
addSignature的上游逻辑,是否存在文档被提前关闭(比如try-with-resources块的范围不合理),或者签名完成后没有正确隔离实例,导致后续操作意外关闭了流。
2. PDFBox 内部流的生命周期管理问题
saveIncrementalForExternalSigning方法会操作PDF内部的COSStream,若之前对文档的操作(比如添加验证信息的步骤)没有正确处理流的关闭,可能导致部分流处于不稳定状态:
- 检查添加验证信息的代码,是否存在手动关闭了文档内部的COSStream但没有重新获取的情况。
- PDFBox的
PDDocument在操作过程中会缓存部分流,若内存不足或GC触发时,可能会自动关闭未使用的流,这种情况下也会间歇性触发异常。
3. 输入流的异常处理问题
传入的inputStream如果在其他地方被共享或提前关闭,也可能间接影响文档内部流的状态。需要确保:
- 每个签名请求使用独立的
InputStream实例,且在签名流程完成前不会被关闭。 generateCMSSignedData方法中是否存在对externalSigningSupport的流进行不当操作(比如提前关闭)。
修复建议
- 确保
PDDocument实例的唯一性:每个签名请求使用独立的PDDocument实例,避免多线程共享同一个实例,且在签名完成后单独关闭文档(注意不要在当前方法内关闭,因为调用方可能还需要使用)。 - 检查上游资源管理:确认调用
addSignature的代码没有在try-with-resources中提前关闭文档,或者在签名流程未完成时触发了文档的关闭操作。 - 避免手动操作内部流:不要直接关闭或操作
PDDocument内部的COSStream,交给PDFBox自行管理生命周期。 - 添加线程安全控制:如果必须多线程处理,对
PDDocument实例的操作添加同步锁,确保同一时间只有一个线程操作该实例。
内容的提问来源于stack exchange,提问作者Tanmay Sharma
相关产品推荐
相关产品推荐

