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

Java 最佳实践:为XMLReader创建SAX解析器,java,spring,tomcat,amazon-s3,sax,Java,Spring,Tomcat,Amazon S3,Sax,我在同一个Tomcat上运行的两次独立战争中使用了AmazonS3SDK。我在我的一个Spring服务的@PostConstruct中初始化了一个AmazonS3Client 如果我单独进行这些战争,一切正常。如果我同时运行它们,其中一个(第二个要启动的)抛出以下异常: com.amazonaws.AmazonClientException:无法为XMLReader初始化sax驱动程序 我有一个变通方法,在捕获AmazonClientException后,如果发生这种情况,我将设置以下系统属性:

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

如果我单独进行这些战争,一切正常。如果我同时运行它们,其中一个(第二个要启动的)抛出以下异常:

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

我有一个变通方法,在捕获AmazonClientException后,如果发生这种情况,我将设置以下系统属性:

try {
  init();
} catch (AmazonClientException ase) {
  System.setProperty("org.xml.sax.driver", "com.sun.org.apache.xerces.internal.parsers.SAXParser");
  init();
}
但这当然很可怕。有更好的方法吗?为什么会出现这种情况


更新:一开始,将AmazonS3Client的初始化从@PostConstruct中移出并延迟初始化似乎完全避免了这个错误。但很明显,有时这种情况仍然会发生——即使我只运行了一场战争而不是两场战争。

XMLReader会通过一系列步骤来确定要使用哪个驱动器。引用文件

  • 如果系统属性org.xml.sax.driver有一个值,则使用该值 作为XMLReader类名
  • JAR“servicesapi”用于查看 中META-INF/services/org.xml.sax.driver文件中的类名 运行时可用的JAR文件
  • SAX解析器发行版是 强烈建议提供默认的XMLReader类名 只有在不使用以前的选项(在此列表中)时,此选项才会生效 成功
  • 最后,如果ParserFactory.makeParser()可以返回 系统默认SAX1解析器,该解析器封装在 帕西雷达。(这是针对SAX1环境的迁移帮助,其中 org.xml.sax.parser系统属性通常可用。)
正在查看

关于这段代码,我有几点不喜欢

  • SAXE异常的根本原因已被耗尽
  • SAXE2异常的根本原因也被消耗殆尽。代码至少应该打印一条提到根本原因的警告
  • 在级别框架代码中使用System.setProperty()可能会导致一些难以调试的问题
    这些要点使得调试问题变得更加困难。我能做出的最好的推测是,crimson解析器在一个类加载路径中是可访问的,但在另一个路径中是不存在的。找到问题的最终方法是在代码上设置一个断点,尝试实例化读取器并找出根本原因。

    由于它使用单例模型,隔离此调用的唯一方法是在WARs本身中设置一整套与SAX相关的JAR(它们将加载到不同的类加载器). 当我遇到同样的问题时,它对我起了作用。这将产生永久性影响,但该怎么办。。 或者,如果您不介意更改S3库,请使此方法静态同步并共享该库。
    如果Amazon的人进行了同步调用,这就不是问题。

    听起来像是类加载器问题。您在tomcat设置中是否做了任何非标准的事情?您是否在WAR中部署了任何xml库(如xerces、xml API等)?您是否尝试过将这些库从WAR中取出并放入ApacheTomcat的认可目录(
    /annowed
    )中?可能会这样-我在共享库中遇到了类似的问题。@jtahlborn:我还假设这是类加载器的问题。我正在使用Jackson-但两场战争都有它,所以我觉得奇怪的是,它只会在它们一起加载时引起问题。@tbk值得一试,但它会对我们的部署过程造成严重破坏。不管怎样都值得去做。@Eyal:事实上,被认可的变体非常糟糕。然而,Tomcat的类加载器有时非常痛苦。我通常会遇到XML解析器的问题。在servlet容器中运行成熟的J2EE服务器可能更适合处理您的问题。如果你不介意你在运行什么样的服务器,你可以看看glassfish。你的最后一段是正确的,但这对我没有帮助,真的。我确实调试过这个,并且可以看到有时候对createXMLReader的调用会失败。但我不知道它为什么会失败——特别是为什么它会在同一个地方失败和成功,这取决于其他战争的情况。正如我在问题中所写的,我有一个修复程序,可以使我所有的Amazon3Client都被初始化,但这并不是解决这种现象的最佳方案。
    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");
            }
        }
    }