如何在CXF管道上设置TLS参数?

时间:2018-08-23 15:47:26

标签: java ssl soap cxf cxf-client

我的应用程序有两个传出SOAP连接。对于这些,我想实现TLS。两者都是使用CXF创建的。

javax.xml.ws.Service.getPort()返回一个单独的bindingProvider(两个连接都使用它们自己的WSDL),但是两者都使用相同的org.apache.cxf.bus.spring.SpringBus实例。

在使用bindingProvider之前,我在管道上设置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);

问题是,两个连接的检索到的客户端不同,但是管道是同一对象。因此,当我在同一对象上设置第二个连接的参数时,我将覆盖先前设置的设置。

常见问题解答答案if CXF is threadsafe带有“是”和许多例外。我认为第二个例外在这里适用。它说:

  

CXF答案:对于许多用例,CXF代理都是线程安全的。例外是:

     
      
  • [...]

  •   
  • 导管上的设置-如果使用代码或配置直接操作导管(例如设置TLS设置或类似设置),则这些设置不是线程安全的。该管道是基于实例的,因此将共享那些设置。另外,如果使用FailoverFeature和LoadBalanceFeatures,则将即时更换导管。因此,在导管上设置的设置在用于设置线程之前可能会丢失。

  •   
  • [...]

  •   
     

对于导管问题,您可以安装一个使用本地或类似线程的新ConduitSelector。不过,这有点复杂。

我不确定线程​​安全是否是我的问题。我在各自的组件中创建了两个连接。 Springs仅使用一个线程来初始化所有组件,因此两个连接都由同一线程初始化。但是之后,该连接将使用来自池的线程。覆盖设置是在初始化期间发生的,因此在使用不同的线程发送实际的SOAP消息之前。

org.apache.cxf.endpoint.AbstractConduitSelector#getSelectedConduit中创建管道时,使用SpringBus来完成,这是两个对象的实例。

因此,常见问题解答告诉我使用我自己的自定义ConduitSelector。 我尝试在上述初始化之前设置它:

Client client = ClientProxy.getClient(bindingProvider);
client.setConduitSelector(
    new UpfrontConduitSelector(
        new URLConnectionHTTPConduit(client.getBus(), 
                                     client.getEndpoint().getEndpointInfo())));

,初始化后我尝试了同样的方法。在这两种情况下,设置管道选择器后,当某些对象使用BindingProvider(它是一个代理对象)时,尽管该对象不为null,它仍会收到NullPointerException。

我的问题是使自定义管道选择器运行,或者看到我的问题可以完全解决,或者只是为了获得启发:)

SO上的某个人似乎已经解决了这个here,但是他的问题的答案对我没有帮助。

1 个答案:

答案 0 :(得分:1)

我找到了解决方法。

这个问题确实与多线程无关,而是与SpringBus连接到我的对象的方式以及如何从中创建导管有关。

解决方案是为每个服务提供自己的SpringBus。

因此,在我通过在javax.xml.ws.Service中调用c'tor创建每个SOAP服务之前,我已经完成

BusFactory bf = BusFactory.newInstance();
Bus b = bf.createBus();
BusFactory.setThreadDefaultBus(b);

设置新的本地线程默认总线,然后将其用于创建的服务。因此,我的两个服务都具有自己的SpringBus,并且它们都创建了自己的管道。

之所以可行,是因为每个服务都是一个弹簧@Component,并且所有弹簧组件都是由主线程创建的。因此,只有一个线程,并且无法按顺序执行此代码。