JAX-WS =当安装了Apache CXF时,它会“窃取”默认的JDK JAX-WS实现,如何解决?

我有一个奇怪的问题。

  1. 使用wsimport我从一个WSDL(在一个专门的eclipse java项目中)生成了als JAX-WS代码。 这在JDK6中工作正常,没有任何外部依赖(在Eclipse中运行)

  2. 我有第二个项目,曾经使用过Apache CXF。 如果我将1.)中描述的代码复制到这个项目中,那么JDK不会执行JAX-WS的东西(我生成的文件),而是执行Apache CXF。

我怎样才能防止Apache CXF“运行”JAX-WS的东西。 (问题是,CXF无法运行代码…)。 我也完全不明白Apache CXF如何发现这些类。 我没有注册他们吗?

非常感谢你! 马库斯

Apache CXF( cxf-rt-frontend-jaxws-*.jar精确)将自己注册为JVM中的JAX-WS提供程序。 在上述JAR中,有一个名为: /META-INF/services/javax.xml.ws.spi.Provider的文件,内容如下:

 org.apache.cxf.jaxws.spi.ProviderImpl 

如果您现在查看javax.xml.ws.spi.FactoryFinder#find方法,则会发现JDKsearchCLASSPATH中是否存在javax.xml.ws.spi.Provider文件,如果不可用,则会回退到缺省的Sun实现。 所以你有两个select来强制回退:

  • 从CLASSPATH中删除cxf-rt-frontend-jaxws-*.jar

  • 或者覆盖CXF提供的指向备用位置的javax.xml.ws.spi.Provider文件

第二个选项实际上更容易一些。 简单地创build:

 /src/main/resources/META-INF/services/javax.xml.ws.spi.Provider 

文件(假设你正在使用Maven),内容如下:

 org.apache.cxf.jaxws.spi.ProviderImpl 

就是这样,用javax.xml.ws.Endpoint#publish进行testing。

对于默认的实现:

 com.sun.xml.internal.ws.spi.ProviderImpl 

在/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider

我试了另一个,我根本无法使它工作,所以要设置CXF,如果它没有设置为CXF,我只是覆盖服务内的委托。

  try { loc = this.getClass().getResource(wsdlResource); QName qName = new QName( wsTargetNamespace, wsName ); service = new YourWS(loc, qName); Field delegateField = Service.class.getDeclaredField("delegate"); //ALLOW CXF SPECIFIC SERVICE DELEGATE ONLY! delegateField.setAccessible(true); ServiceDelegate previousDelegate = (ServiceDelegate) delegateField.get(service); if (!previousDelegate.getClass().getName().contains("cxf")) { ServiceDelegate serviceDelegate = ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()) .createServiceDelegate(loc, qName, service.getClass()); log.info("The " + getClass().getSimpleName() + " delegate is changed from " + "[" + previousDelegate + "] to [" + serviceDelegate + "]"); delegateField.set(service, serviceDelegate); } port = service.getYourWSSoap(); 

标准的查找机制在OSGi(*)中似乎不太适用。

有两种方法来强制服务来获取javax.xml.ws.spi.Provider的CXF实现:

  • 通过EpicPandaForce对这个问题的回答( https://stackoverflow.com/a/31892305/109079 )给出的reflection来设置delegate的方法,

  • 调用较低级别的JaxWsProxyFactoryBean ; 这似乎可以避免所有对Java中包含的javax.xml.ws.spi.FactoryFinder调用,这是问题的根源

以下是后者的一个例子,对于那些不想reflection性地改变私人领域的不太强大的编码者来说:

 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.getClientFactoryBean().getServiceFactory().setWsdlURL(WinRmService.WSDL_LOCATION); factory.setServiceName(WinRmService.SERVICE); factory.setEndpointName(WinRmService.WinRmPort); // factory.setFeatures(...); // if required Service winrm = factory.create(WinRm.class); Client client = ClientProxy.getClient(winrm); 

几个注意事项:

  • 如果WSDL是类path上的资源(可避免无法parsing的bundle://...类path项的URL factory.setWsdlURL(String)可能需要传递上面的URL ,而不是简单的factory.setWsdlURL(String)

  • 您可能需要额外的捆绑function(如寻址)


(*) 至于为什么查找机制在大多数OSGi容器中不起作用,请在Oracle Java的FactoryFinder查看这一点令人讨厌的内容:

 private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "com.sun.org.glassfish.hk2.osgiresourcelocator.ServiceLoader"; private static boolean isOsgi() { try { Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME); return true; } catch (ClassNotFoundException ignored) { } return false; } 

OSGi = Glassfish? 真是腥!