代码之家  ›  专栏  ›  技术社区  ›  Roman Puchkovskiy

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

  •  1
  • Roman Puchkovskiy  · 技术社区  · 7 年前

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

    Endpoint.publish(url, impl);
    

    Provider 运行时通过 ServiceLoader 机制。如果我正确理解了代码,运行时只会选择第一个 实现返回者 服务加载器

    我想避免这样。我知道JDK附带了一个默认的JAX-WS实现(在我的例子中,它是jdk8)。是否可以排除CXF 供应商 或者优先选择要首先选取的默认值?(最好不要像从cxfjar中删除服务文件定义这样的黑客攻击)。

    2 回复  |  直到 7 年前
        1
  •  1
  •   VGR    7 年前

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

    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.");
    }
    
        2
  •  0
  •   Roman Puchkovskiy    7 年前

    Endpoint.publish() 寻找一个 Provider 这样地:

    1. 得到一个 Iterator ServiceLoader 取这个迭代器的第一个元素
    2. 仅限 如果 为空,继续回退 供应商

    端点.发布()

    供应商 ServiceProvider (缺省情况下,JDK提供的是 可通过 ).

    我尝试使用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. 我使用反射是因为 是一个内部实现类 javac
    2. javax.xml.bind.JAXBContext 已经开始工作了 java.lang.ClassCastException: blablabla$JaxbAccessorF_bin cannot be cast to com.sun.xml.bind.v2.runtime.reflect.Accessor
    推荐文章