最佳实践:为XMLReader创建SAX解析器

时间:2012-08-29 14:44:38

标签: java spring tomcat amazon-s3 sax

我在同一个Tomcat上运行的两个单独的战争中使用Amazon S3 SDK。我在我的一个Spring服务的@PostConstruct中初始化了一个AmazonS3Client。

如果我分开运行这些战争,一切通常都可以。如果我一起运行它们中的一个 - 第二个启动它 - 抛出以下异常:

  

com.amazonaws.AmazonClientException:无法初始化XMLReader的sax驱动程序

我有一个解决方法,在捕获AmazonClientException后,如果发生这种情况,我会设置以下System属性:

try {
  init();
} catch (AmazonClientException ase) {
  System.setProperty("org.xml.sax.driver", "com.sun.org.apache.xerces.internal.parsers.SAXParser");
  init();
}

但这当然是可怕的。有一个更好的方法吗?为什么会出现这种情况?

更新:首先,似乎将AmazonS3Client的初始化移出@PostConstruct并且懒洋洋地初始化它可以完全阻止此错误。但显然有时候它仍然会发生 - 即使我只运行一次战争而不是两次。

2 个答案:

答案 0 :(得分:5)

XMLReader通过一系列步骤来识别要使用的驱动器。引用文档

  • 如果系统属性org.xml.sax.driver具有值,则使用该值 作为XMLReader类名。
  • JAR“服务API”用于查看 对于META-INF / services / org.xml.sax.driver文件中的类名称 jarfiles可用于运行时。
  • SAX解析器分发是 强烈建议提供一个默认的XMLReader类名 仅在先前的选项(在此列表中)不生效时才会生效 成功的。
  • 最后,如果ParserFactory.makeParser()可以返回一个 系统默认SAX1解析器,该解析器包装在一个 ParserAdapter。 (这是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");
        }
    }
}

我不喜欢这些代码。

  1. SaxException e的根本原因被吃掉了。
  2. SaxException e2的根本原因也被吃掉了。代码应该做的最少就是打印一个警告,提到根本原因。
  3. 在级别框架代码中使用System.setProperty()可能会导致一些难以调试的问题。
  4. 这些要点使调试问题变得更加困难。我能做出的最有根据的猜测是,深红色解析器可以在一个类加载路径中访问,但在另一个类加载路径中不存在。找到问题的结论性方法是在代码上设置一个断点,试图实例化读者并查找根本原因是什么。

答案 1 :(得分:1)

因为它使用单例模型,隔离此调用的唯一方法是在WAR本身内拥有整套与SAX相关的JAR(它们将加载到不同的类加载器)。当我遇到同样的问题时,它对我有用。这将产生PermGen影响,但该怎么做.. 或者,如果您不介意更改S3 lib,请使此方法静态同步并共享lib。 如果亚马逊的家伙让这个呼叫同步,这不会是问题。