如何在java中覆盖服务提供程序

这更像是一个通用的问题:我正在使用xstream和woodstox,woodstox附带了javax的服务提供商.xml.stream.XMLOutputFactory in woodstox jar注册com.ctc.wstx.stax.WstxOutputFactory。我想提供我自己的javax.xml.stream.XMLOutputFactory,并且在类路径中仍然有woodstox jar。我知道我可以提供我自己的系统属性javax.xml.stream.XMLOutputFactory,但我试图摆脱我们开发运维团队的麻烦,并使用我的jar中的服务文件或我的war的META-INF / services文件夹中。查看javax.xml.stream.FactoryFinder的代码,我如何确保我的META-INF/services/javax.xml.stream.XMLOutputFactory文件将是FactoryFinder使用的那个?

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


答案 1

首先:与其依赖JDK SPI接口,我强烈建议简化你的生活,不要使用它。它真的比注射和/或你自己没有增加任何价值。对于注射,您可以使用Guice(或弹簧);或者只是手动传递它。由于这些工厂没有自己的依赖关系,因此这很容易。XMLInputFactoryXMLOutputFactory

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

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

  1. 它增加了开销:如果您没有指定System属性,它将不得不扫描整个类路径,而对于大型应用程序服务器,这需要10x-100x,只要大多数解析
  2. 实现的优先级是未定义的:如果你在类路径中多次,你会得到哪一个?谁知道呢。。。(请注意:当您在类路径中添加新的jar时,它甚至可能会更改)
  3. 您很可能通过传递依赖项获得多个 impl

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


答案 2

您可以像这样指定要使用的 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

XMLInputFactory.newInstance() 方法派生自 JAXP,通过使用下面的查找过程确定要加载的特定 XMLInputFactory 实现类:

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

推荐