我在同一个 Tomcat 上运行的两个独立 war 中使用 Amazon S3 SDK。我在我的一项 Spring 服务的 @PostConstruct 中初始化了一个 AmazonS3Client。
如果我分别运行这些 war ,通常一切正常。如果我一起运行它们,其中一个 - 第二个启动 - 会抛出以下异常:
com.amazonaws.AmazonClientException: Couldn't initialize a sax driver for the XMLReader
我有一个解决方法,如果发生这种情况,我会在捕获 AmazonClientException 后设置以下系统属性:
try {
init();
} catch (AmazonClientException ase) {
System.setProperty("org.xml.sax.driver", "com.sun.org.apache.xerces.internal.parsers.SAXParser");
init();
}
但这当然很可怕。有一个更好的方法吗?为什么会在这些情况下发生?
更新:起初,似乎将 AmazonS3Client 的初始化移出 @PostConstruct 并延迟初始化它可以完全防止此错误。但显然它有时仍然会发生 - 即使我只发动一场 war 而不是两场 war 。
最佳答案
XMLReader 通过一系列步骤来识别要使用的驱动器。引用文档
- 如果系统属性 org.xml.sax.driver 有值,则使用 作为 XMLReader 类名。
- JAR“服务API”用于查看 对于 META-INF/services/org.xml.sax.driver 文件中的类名 运行时可用的 jar 文件。
- SAX 解析器分布是 强烈建议提供默认的 XMLReader 类名 仅当先前的选项(在此列表中)不存在时才会生效 成功的。
- 最后,如果 ParserFactory.makeParser() 可以返回一个 系统默认 SAX1 解析器,该解析器包装在 解析器适配器。 (这是 SAX1 环境的迁移帮助,其中 org.xml.sax.parser 系统属性通常可用。)
查看 AWS SDK 的代码...
public XmlResponsesSaxParser() throws AmazonClientException {
// Ensure we can load the XML Reader.
try {
xr = XMLReaderFactory.createXMLReader();
} catch (SAXException e) {
// oops, lets try doing this (needed in 1.4)
System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");
try {
// Try once more...
xr = XMLReaderFactory.createXMLReader();
} catch (SAXException e2) {
throw new AmazonClientException("Couldn't initialize a sax driver for the XMLReader");
}
}
}
我不喜欢该代码的一些地方。
- SaxException e 的根本原因被吃光了。
- SaxException e2 的根本原因也被吃掉了。代码至少应该打印一条警告,提及根本原因。
- 在级别框架代码中使用 System.setProperty() 会导致一些难以调试的问题。
这些点使得调试问题变得更加困难。我能做出的最有根据的猜测是 crimson 解析器可以在一个类加载路径中访问,但在另一个类加载路径中不存在。找到问题的决定性方法是在尝试实例化读取器的代码上设置断点,并找出根本原因是什么。
关于java - 最佳实践 : Creation of SAX parser for XMLReader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12180606/