我有一些最初用于单线程处理的代码,现在由多个线程使用。我在未修改且通常工作正常的 xsl 上遇到了奇怪的 xsl 解析错误。
我不寻求代码修正,我将通过我自己的研究重构此类以实现线程安全。欢迎提供有关此问题的提示,但对于答案来说不是必需的。
我寻求解释可能/可能发生的情况,从而产生下面看到的奇怪错误。
例如线程A进入代码X行,在Y行停止,线程B进入X行,读取流S,停止。线程 A 现在执行 Z 来传输 S 并损坏它...等等。我模糊的预感是,当 2 个线程同时操作/读取对象“xsl”时,它会以某种方式损坏,但我缺乏对 InputStream 对象和 Source 对象如何进行的了解在 api 内部工作。
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
...
</xsl:stylesheet>
样式表应该没问题。如果您不这么认为,请告诉我。
错误:
[Fatal Error] :1:33: The encoding declaration is required in the text declaration.
[Fatal Error] :1:2: Content is not allowed in prolog.
Couldn't create transformer object for xsl javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet
这些错误发生了很多次,并且一直持续到应用程序重新启动为止。这些显然都指向一个错误的 xsl。但我确实验证了该文件没有损坏。
Java代码:
public class IntegrationRequest {
private static Source xsl; // data that i believe got corrupted
private static Transformer inputTransformer;
private static JAXBContext createContext;
...
// this public method is now executed by multiple threads at once
public String getResponse() {
createTransformerInstance(); // err thrown in here
String xmlRequest = getXmlRequestString();
String response = executeRequest(createHttpConnection(), xmlRequest);
return response;
}
private static Transformer createTransformerInstance() {
if (inputTransformer == null) {
TransformerFactory factory = TransformerFactory.newInstance();
try {
inputTransformer = factory.newTransformer(getXSLTemplate("/Integration_Request.xsl"));
} catch (TransformerConfigurationException e) {
if (log.isErrorEnabled()) {
log.error("Couldn't create transformer object for xsl ", e);
}
}
}
return inputTransformer;
}
private static Source getXSLTemplate(String fileName) {
if (xsl == null) {
InputStream xslInputStream = IntegrationRequest.class.getClassLoader().getResourceAsStream(fileName);
xsl = new StreamSource(xslInputStream);
}
return xsl;
}
}
注意 getXSLTemplate 如何缓存 xsl - 应用程序将保留该错误数据直到重新启动。这是我的理论的基础,即它在第一次加载时被多个线程损坏。
最佳答案
这些错误表明样式表解析失败 - XML 解析器在读取样式表文档时没有看到有效的 XML。发生这种情况很可能是因为两个或多个线程开始创建样式表,所有线程都在 xsl
变量中使用相同的 InputStream
。一种可能的情况是:
- 线程 1 第一次调用
getResponse
,创建xsl
,线程 1 开始从xsl
读取。 - 线程 2 调用
getResponse
,也没有看到非空transformer
,开始从同一个xsl
读取,从而破坏了解析线程 1 中的进程。
请注意,Transformer
也不是线程安全的类。您应该使用 javax.xml.transform.Templates
来代替,并从 Templates
为每个转换创建一个 Transformer
。
关于Java 输入流/XSL 线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35900809/