如何在java中覆盖服务提供者

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

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

第一:我强烈建议简化你的生活而不是使用JDK SPI接口,而不是依靠JDK SPI接口。 它实际上没有增加自己注入XMLInputFactory和/或XMLOutputFactory价值。 对于注射,您可以使用Guice(或Spring); 或者只是手动传递它。 由于这些工厂没有自己的依赖关系,这很容易。

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

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

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

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

你可以这样做来指定你想要使用的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系统属性。
  2. 使用JRE目录中的lib / xml.stream.properties文件。
  3. 如果可用,请使用Services API通过查看JRE可用的jar中的META-INF / services / javax.xml.stream.XMLInputFactory文件来确定类名。
  4. 使用平台默认的XMLInputFactory实例。

我发现如果我将服务文件放在WEB-INF / classes / services / javax.xml.stream.XMLOutputFactory下,那么它将首先在classpath中,然后在WEB-INF / lib中的jars之前。 那是我的解决方案。

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

而本地读者则是com.sun.xml.internal.stream.XMLEventReaderImpl

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

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

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