JAX-WS =当安装了Apache CXF时,它会“窃取”默认的JDK JAX-WS实现,如何解决?
我有一个奇怪的问题。
-
使用wsimport我从一个WSDL(在一个专门的eclipse java项目中)生成了als JAX-WS代码。 这在JDK6中工作正常,没有任何外部依赖(在Eclipse中运行)
-
我有第二个项目,曾经使用过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项的URLfactory.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? 真是腥!