是否可以避免使用通过META-INF中的服务定义获取的JAX-WS提供程序?

时间:2018-09-28 17:06:58

标签: java cxf jax-ws

我正在使用以下行来启动JAX-WS端点:

Endpoint.publish(url, impl);

我在类路径上有CXF,因此其Provider实现由运行时通过ServiceLoader机制获取。如果我正确理解代码,则运行时将选择Provider返回的第一个ServiceLoader实现。结果,CXF端点启动。

我想避免这种情况。我知道JDK附带了默认的JAX-WS实现(在我的情况下是JDK 8)。是否可以排除CXF Provider或优先处理要优先使用的默认值? (最好不要像从CXF jar中删除服务文件定义这样的黑客程序。)

2 个答案:

答案 0 :(得分:1)

应该可以自己找到提供者:

public static Endpoint publish(String address,
                               Object implementor) {

    for (Provider provider : ServiceLoader.load(Provider.class)) {
        if (!provider.getClass().getName().contains("cxf")) {
            return provider.createAndPublishEndpoint(address, implementor);
        }
    }

    throw new RuntimeException(
        "No non-CXF JAW-WS provider found in classpath.");
}

答案 1 :(得分:0)

Endpoint.publish()查找这样的Provider

  1. Iterator获取一个ServiceLoader,并获取此迭代器的第一个元素
  2. ,如果Iterator为空,请继续使用备用Provider分辨率

就我而言,迭代器中总有东西,因此Endpoint.publish()不是一个选择。

我也尝试了@VGR建议的解决方案,但是它没有用,因为我没有Provider可用的其他ServiceProvider实现(默认情况下,JDK附带的实现是<可以通过ServiceProvider使用strong>不。

我尝试使用Metro RT添加其他提供商:

<dependency>
    <groupId>com.sun.xml.ws</groupId>
    <artifactId>rt</artifactId>
    <version>2.3.0</version>
    <scope>test</scope>
</dependency>

但是后来我遇到了另一个问题:

java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to javax.xml.soap.SOAPElement

这可能是由于Metro和旧版本的CXF都在类路径上造成的。

对我有用的方法不是很优雅:我只是直接实例化了默认的com.sun.xml.internal.ws.spi.ProviderImpl(使用反射),并为偶然发现的变通问题添加了一些系统属性:

System.setProperty("javax.xml.bind.JAXBContext", "com.sun.xml.internal.bind.v2.ContextFactory");
Endpoint endpoint =  createWSProvider().createAndPublishEndpoint(url, impl);

private static Provider createWSProvider() {
    final String className = "com.sun.xml.internal.ws.spi.ProviderImpl";

    Class<?> aClass;
    try {
        aClass = Class.forName(className);
    } catch (ClassNotFoundException e) {
        throw new RuntimeException(e);
    }

    try {
        return (Provider) aClass.getConstructor().newInstance();
    } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
        throw new RuntimeException(e);
    }
}
  1. 我之所以使用反射,是因为com.sun.xml.internal.ws.spi.ProviderImpl是内部实现类,而javac会拒绝看到它。
  2. javax.xml.bind.JAXBContext已设置为可以解决java.lang.ClassCastException: blablabla$JaxbAccessorF_bin cannot be cast to com.sun.xml.bind.v2.runtime.reflect.Accessor