我的应用程序有两个传出 SOAP 连接。对于那些,我想实现 TLS。两者都是使用 CXF 创建的。
返回一个单独的javax.xml.ws.Service.getPort()
bindingProvider(两个连接都使用自己的 WSDL),但都使用相同的org.apache.cxf.bus.spring.SpringBus
实例。
在使用 bindingProvider 之前,我在 Conduit 上设置了 TLS 客户端参数:
Client client = ClientProxy.getClient(bindingProvider); // different
HTTPConduit httpConduit = (HTTPConduit) client.getConduit(); // same for both connections
TLSClientParameters tlsClientParameters = new TLSClientParameters();
tlsClientParameters.setTrustManagers(getTrustmanagers());
httpConduit.setTlsClientParameters(tlsClientParameters);
问题是,检索到的客户端对于两个连接都不同,但管道是同一个对象。因此,当我在同一对象上设置第二个连接的参数时,我会覆盖先前设置的设置。
常见问题解答是否 CXF 是线程安全的,“是”和一些例外情况。我认为第二个例外适用于此。它说:
CXF 回答: CXF 代理对于许多用例来说都是线程安全的。例外情况是:
[...]
管道上的设置 - 如果您使用代码或配置直接操作管道(例如设置 TLS 设置或类似设置),则这些不是线程安全的。管道是每个实例的,因此这些设置将被共享。此外,如果您使用 FailoverFeature 和 LoadBalanceFeatures,则会即时更换管道。因此,在导管上设置的设置在用于设置线程之前可能会丢失。
[...]
对于导管问题,您可以安装一个使用本地线程或类似线程的新 ConduitSelector。不过这有点复杂。
我不完全确定线程安全是否是我的问题。我在各自的组件中创建了两个连接。Springs 只使用一个线程来初始化所有组件,因此两个连接都由同一个线程初始化。但之后,连接使用了来自池的线程。覆盖设置发生在初始化期间,因此在使用不同线程发送实际 SOAP 消息之前。
当在 中创建 Conduit 时org.apache.cxf.endpoint.AbstractConduitSelector#getSelectedConduit
,它是使用SpringBus
两个对象的相同实例来完成的。
所以,FAQ 告诉我使用我自己的自定义 ConduitSelector。我尝试在上面的初始化之前设置它:
Client client = ClientProxy.getClient(bindingProvider);
client.setConduitSelector(
new UpfrontConduitSelector(
new URLConnectionHTTPConduit(client.getBus(),
client.getEndpoint().getEndpointInfo())));
我在初始化后尝试了同样的方法。在这两种情况下,在设置了管道选择器之后,当某些东西使用 BindingProvider(它是一个代理对象)时,它会得到一个 NullPointerException,尽管该对象不为空。
我的问题是让自定义管道选择器运行,或者看看我的问题可以完全不同地解决,或者只是为了获得一些灵感:)
SO上的某个人似乎在这里解决了这个问题,但他的问题的答案对我没有帮助。