Wildfly:如何使用 JAXWS-RI 而不是 Apache CXF(仅限 WebService 客户端)

Wildfly: How to use JAXWS-RI instead of Apache CXF (WebService client only)

我的环境是 Maven 项目和 Wildfly (8.2.1) 作为应用程序服务器。我需要的是使用 SOAP 将传入的 REST 调用连接到第三方服务器。我需要 SSL 客户端身份验证;因此,我有自己的 KeyStore 和 TrustStore。因此,我创建了自己的 SSLContext 并需要让 WebService 使用此 SSLContext。

一切看起来像这样:

// Build SSL context with own KeyManager / TrustManager
SSLContext sc = SSLContext.getInstance("TLS");

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

KeyStore ks = KeyStore.getInstance("JKS");
String password = "changeit";
ks.load(getClass().getResourceAsStream("/keystore"), password.toCharArray());

kmf.init(ks, password.toCharArray());

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);

sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

// Now build webservice client
MyWS_Service service = new MyWS_Service(null, new QName("http://...", "MyWS"));
MyWS port = service.getMyWSSOAP();

BindingProvider bindingProvider = (BindingProvider) port;

// set to use own SSLContext
bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sc.getSocketFactory());
// set endpoint
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://hostname:443/.../...");

// perform request
respObj = port.myRequest(myRequestObj);

如果我从 JUnit 测试中调用此代码,一切正常。它使用来自 JRE 的 JAXWS-RI。

如果我从 Wildfly 调用此代码,即从我传入的 REST 调用,我最终需要触发此请求,它不起作用,因为它不使用自己的 SSLContext。它使用默认的 SSLContext,这当然会被第三方 SOAP 服务器拒绝。我看到的是它不使用 JAXWS-RI 而是使用 Apache CXF 作为 JAXWS 实现。所以我猜想 bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sc.getSocketFactory()); 只是被忽略了 [] 并且没有任何效果。 (我也尝试了 属性 名称 com.sun.xml.ws.transport.https.client.SSLSocketFactory [没有 internal] - 也没有运气。)

我知道我可以使用 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()),甚至可以使用 JVM 参数 javax.net.ssl.trustStorejavax.net.ssl.keyStore(及其相应的密码属性)。由于这会影响所有连接,因此不讨论使用此解决方案;但是,让我们看看如果我仍然使用它会发生什么:

编辑: 还有一个证明,问题出在 Wildfly 使用的 JAXWS 实现:如果我只是执行一个简单的 HttpsConnection,它甚至可以在 Wildfly 中使用我自己的 KeyStore / TrustStore:

url = new URL("https://hostname:443/.../...");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
System.out.println(Utils.inputStreamToString(con.getInputStream()));

那么最好做什么呢? -> 作为问题标题,我想尝试让 Wildfly 也使用 JAXWS-RI 而不是 Apache CXF。但是直到现在我才开始工作。我试图在 pom 中添加以下依赖项:

    <dependency>
        <groupId>com.sun.xml.ws</groupId>
        <artifactId>jaxws-rt</artifactId>
        <version>2.2.10</version>
    </dependency>

但这给了我以下异常:

java.util.ServiceConfigurationError: javax.xml.ws.spi.Provider: Provider com.sun.xml.ws.spi.ProviderImpl could not be instantiated
    at java.util.ServiceLoader.fail(ServiceLoader.java:232) ~[?:1.8.0_92]

怎么了?我怎样才能让 Wildfly 以同样的方式工作,就好像代码是从同一个项目执行的但是 "as a JUnit Test"?

编辑: 如果您知道如何以不同的方式达到目标(在 Wildfly 8.2.1 上使用带有客户端身份验证的 SSL 发送 SOAP 请求)(前提是它是一个干净的 Java EE 解决方案 - 即不发送自己的 XML bodys :-) 而不是像 Axis 1) 这样的太旧的框架,它也很受欢迎! 我很快就需要一个解决方案 - 我已经奋斗了好几天...

我觉得很难。某处对此有一些评论。顺便说一句,我认为 WildFly 使用的是 RESTEasy,而不是 CXF

OK,最后,我放弃尝试替换使用的JAX-WS实现。我得到它以正确设置 Apache CXF。

这解决了问题:。 Wildfly 将使用 sun 实现而不是 apache.cxf