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

时间:2011-06-15 21:03:04

标签: java web-services jax-ws cxf

我有一个奇怪的问题。

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

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

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

    非常感谢! 马库斯

5 个答案:

答案 0 :(得分:57)

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方法,您将发现JDK在CLASSPATH中搜索javax.xml.ws.spi.Provider文件的存在,如果不可用,则回退到默认的Sun实现。所以你有两种方法可以强制回退:

  • 从CLASSPATH

  • 中删除cxf-rt-frontend-jaxws-*.jar
  • 或覆盖CXF提供的javax.xml.ws.spi.Provider文件以指向后备位置

第二种选择实际上更容易一些。只需创建:

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

文件(假设您正在使用Maven),其中包含以下内容:

org.apache.cxf.jaxws.spi.ProviderImpl

就是这样,用javax.xml.ws.Endpoint#publish测试。

答案 1 :(得分:16)

对于默认实现put:

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

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

答案 2 :(得分:7)

我尝试了另一个,我根本无法使其工作,所以要设置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();

答案 3 :(得分:2)

标准查找机制似乎在OSGi(*)中运行良好。

我有两种方法可以帮助服务获取javax.xml.ws.spi.Provider的CXF实现:

  • 通过EpicPandaForce对此问题的回答(https://stackoverflow.com/a/31892305/109079

  • 的反映来设置delegate的方法
  • 调用较低级JaxWsProxyFactoryBean;这似乎避免了对Java中包含的javax.xml.ws.spi.FactoryFinder的所有调用,这是问题的根源

以下是后者的一个例子,对于那些不喜欢不反思改变私人领域的不那么强悍的程序员来说:

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是类路径上的资源,则可能需要如上所述传递URL而不是更简单的factory.setWsdlURL(String)(避免类路径项的不可解析的bundle://... URL)

  • 您可能需要其他功能包(例如寻址)

(*)至于为什么查找机制在大多数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?确实可疑!

答案 4 :(得分:1)

我有类似的问题。在我的情况下,我必须使用org.apache.cxf.jaxws.spi.ProviderImpl用于JAX-WS(创建webservice端点等)和com.sun.xml.internal.ws.spi.ProviderImpl用于在com.sun.net.httpserver.HttpsServer上发布端点。

我设法通过创建我自己的提供程序来解决这个问题,该提供程序扩展javax.xml.ws.spi.Provider并使用它而不是默认的提供程序。

package provider;

import java.net.URL;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.ws.Endpoint;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.spi.Provider;
import javax.xml.ws.spi.ServiceDelegate;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.w3c.dom.Element;

public class MyProvider extends Provider
{

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public ServiceDelegate createServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class serviceClass)
{
    try {
        return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).createServiceDelegate(wsdlDocumentLocation, serviceName, serviceClass.getClass());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public Endpoint createEndpoint(String bindingId, Object implementor)
{
    try {
        return ((Provider) Class.forName("com.sun.xml.internal.ws.spi.ProviderImpl").newInstance()).createEndpoint(bindingId, implementor);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public Endpoint createAndPublishEndpoint(String address, Object implementor)
{
    try {
        return ((Provider) Class.forName("com.sun.xml.internal.ws.spi.ProviderImpl").newInstance()).createAndPublishEndpoint(address, implementor);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public EndpointReference readEndpointReference(Source eprInfoset)
{
    try {
        return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).readEndpointReference(eprInfoset);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public <T> T getPort(EndpointReference endpointReference, Class<T> serviceEndpointInterface, WebServiceFeature... features)
{
    try {
        return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).getPort(endpointReference, serviceEndpointInterface, features);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public W3CEndpointReference createW3CEndpointReference(String address, QName serviceName, QName portName, List<Element> metadata, String wsdlDocumentLocation, List<Element> referenceParameters)
{
    try {
        return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).createW3CEndpointReference(address, serviceName, portName, metadata, wsdlDocumentLocation,
                referenceParameters);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

}

然后简单地创建:

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

文件(假设您正在使用Maven),其中包含以下内容:

package.MyProvider