【问题标题】:how to override a service provider in java如何在java中覆盖服务提供者
【发布时间】:2013-07-22 08:12:15
【问题描述】:

这是一个更一般的问题示例: 我正在使用 xstream 和woodstox,woodstox 在woodstox jar 注册com.ctc.wstx.stax.WstxOutputFactory 中附带了javax.xml.stream.XMLOutputFactory 的服务提供程序。 我想提供我自己的 javax.xml.stream.XMLOutputFactory 并且在类路径中仍然有woodstox jar。我知道我可以提供自己的系统属性 javax.xml.stream.XMLOutputFactory ,但我正试图从我们的开发运营团队中解脱出来,并使用我的 jar 中的服务文件或战争的 META 中的服务文件来完成-INF/服务文件夹。查看 javax.xml.stream.FactoryFinder 的代码我如何确保我的 META-INF/services/javax.xml.stream.XMLOutputFactory 文件将是 FactoryFinder 使用的文件吗?

我们将 xstream 与骆驼一起使用,但找不到将工厂注入 XStreamDataFormat 的方法

【问题讨论】:

    标签: java stax serviceloader woodstox service-factory


    【解决方案1】:

    如果您的实现在 jar 中,请确保它在类路径上的 woodstox.jar 之前,然后 FactoryFinder 将使用您的实现。

    【讨论】:

    • 问题是如何保证它在类路径上的 Woodstox 之前,尤其是当您使用应用容器(例如 Tomcat)时。
    【解决方案2】:

    我发现如果我把服务文件放在 WEB-INF/classes/services/javax.xml.stream.XMLOutputFactory 那么它将首先出现在类路径中,然后在 WEB-INF/lib 中的 jar 之前。 这就是我的解决方案。

    【讨论】:

    • 我正在解决类似的问题 - 我需要覆盖 Jersey SpringComponentProvider。这个建议对我不起作用,因为 META-INF/services 的路径在 Jersey 内部是硬编码的。我不想投反对票,因为 OP 是关于 XMLOutputFactory 的,但是这个建议不能被视为通用的。
    • WEB-INF/classes/services/javax.xml.stream.XMLOutputFactory 文件的内容是什么?它只是一个类名,还是别的什么?
    • @vikingsteve 这是一个文件名,应该包含您自己实现的完整类名。
    【解决方案3】:

    首先:我强烈建议您简化生活而不是使用它,而不是依赖 JDK SPI 接口。与自己注入 XMLInputFactory 和/或 XMLOutputFactory 相比,它确实没有任何价值。对于注入,您可以使用 Guice(或 Spring);或者只是手动传递。由于这些工厂没有自己的依赖项,因此这很容易。

    但如果选择(或必须)使用XMLInputFactory.newInstance(),您可以为“javax.xml.stream.XMLOutputFactory”和“javax.xml.stream.XMLInputFactory”定义一个系统属性。

    那么为什么不使用 JDK 方法呢?多种原因:

    1. 它增加了开销:如果您没有指定 System 属性,它必须扫描整个类路径,并且对于大型应用服务器,这需要 10 倍到 100 倍的大部分解析时间
    2. 实现的优先级未定义:如果您在类路径中使用多个,您将获得哪一个?谁知道...(请注意:当您在类路径中添加新 jar 时,它甚至可能会改变)
    3. 你很可能通过传递依赖获得多个 impl

    不幸的是,Oracle 似乎仍然坚持添加这种众所周知的错误方法来注册服务提供商。为什么?可能是因为他们没有自己的 DI 库/框架(Guice 来自 google,Spring 来自 Springsource),而且他们往往非常渴望控制。

    【讨论】:

    • 我们将 xstream 与骆驼一起使用,但我没有找到将工厂注入 XStreamDataFormat 的方法。我将代码添加到原始帖子中。但我认为如果我将 META-INF/services 放在我的 WEB-INF/classes 中,是否会首先在类路径中进行扫描。
    • 啊,是的。传递依赖有点讨厌,尤其是。通过两个层次。但是设置系统属性应该可以正常工作——它会比添加 SPI 元数据更快(无类路径扫描)。
    • 为了完整起见,以下是 Javadocs (docs.oracle.com/javase/7/docs/api/javax/xml/stream/…) 所说的:“使用 javax.xml.stream.XMLInputFactory 系统属性。使用 JRE 中的属性文件“lib/stax.properties”目录”
    【解决方案4】:

    您可以这样做来指定您要使用的 XMLOutputFactory 实现:

    System.setProperty("javax.xml.stream.XMLOutputFactory", ... full classname You want to use ...);
    

    来源: http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/SJSXP4.html

    从 JAXP 派生的 XMLInputFactory.newInstance() 方法 确定要加载的具体 XMLInputFactory 实现类 通过使用以下查找过程:

    1. 使用 javax.xml.stream.XMLInputFactory 系统属性。
    2. 使用 JRE 目录中的 lib/xml.stream.properties 文件。
    3. 使用服务 API(如果可用)通过查看 META-INF/services/javax.xml.stream.XMLInputFactory 来确定类名 JRE 可用的 jar 中的文件。
    4. 使用平台默认的 XMLInputFactory 实例。

    【讨论】:

      【解决方案5】:

      我们遇到了类似的问题,解析将在本地运行但在服务器上失败。调试后发现服务器正在使用阅读器com.ctc.wstx.evt.WstxEventReader

      而在本地阅读器上是com.sun.xml.internal.stream.XMLEventReaderImpl

      我们设置了以下属性来解决它。

      System.setProperty("javax.xml.stream.XMLInputFactory", "com.sun.xml.internal.stream.XMLInputFactoryImpl");
      

      【讨论】:

        猜你喜欢
        • 2014-07-10
        • 1970-01-01
        • 2017-07-23
        • 2023-03-28
        • 2011-08-05
        • 2021-09-29
        • 2012-08-07
        • 2016-01-02
        • 2017-03-05
        相关资源
        最近更新 更多