这个JAX-WS客户端调用线程是否安全?

use*_*611 30 java java-metro-framework jax-ws webservice-client

由于WS客户端服务和端口的初始化需要很长时间,所以我喜欢在启动时初始化它们并重用相同的端口实例.初始化看起来像这样:

private static RequestContext requestContext = null;

static
{
    MyService service = new MyService(); 
    MyPort myPort = service.getMyServicePort(); 

    Map<String, Object> requestContextMap = ((BindingProvider) myPort).getRequestContext();
    requestContextMap = ((BindingProvider)myPort).getRequestContext(); 
    requestContextMap.put(BindingProvider.USERNAME_PROPERTY, uName); 
    requestContextMap.put(BindingProvider.PASSWORD_PROPERTY, pWord); 

    rc = new RequestContext();
    rc.setApplication("test");
    rc.setUserId("test");
}
Run Code Online (Sandbox Code Playgroud)

我班上某个地方的电话:

myPort.someFunctionCall(requestContext, "someValue");
Run Code Online (Sandbox Code Playgroud)

我的问题:这个调用是否是线程安全的?

kyi*_*yiu 31

根据CXF FAQ:

JAX-WS客户端代理是否安全?

官方JAX-WS回答:不可以.根据JAX-WS规范,客户端代理不是线程安全的.要编写可移植代码,您应将它们视为非线程安全并同步访问或使用实例池或类似代码.

CXF回答:对于许多用例,CXF代理是线程安全的.例外情况是:

  • 使用((BindingProvider)proxy).getRequestContext()- 根据JAX-WS规范,请求上下文是PER INSTANCE.因此,那里设置的任何东西都会影响其他线程的请求.使用CXF,您可以:

    ((BindingProvider)proxy).getRequestContext().put("thread.local.request.context","true");
    
    Run Code Online (Sandbox Code Playgroud)

    以及对getRequestContext()的调用将使用线程本地请求上下文.这允许请求上下文是线程安全的.(注意:响应上下文始终是CXF中的线程本地)

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

  • 会话支持 - 如果启用会话支持(请参阅jaxws规范),会话cookie将存储在管道中.因此,它将落入管道设置的上述规则,因此可以跨线程共享.
  • WS-Security令牌 - 如果使用WS-SecureConversation或WS-Trust,则检索到的令牌将缓存在端点/代理中,以避免对STS进行额外(且昂贵)调用以获取令牌.因此,多个线程将共享令牌.如果每个线程具有不同的安全凭据或要求,则需要使用单独的代理实例.

对于管道问题,您可以安装一个使用本地或类似线程的新ConduitSelector.虽然这有点复杂.

对于大多数"简单"用例,您可以在多个线程上使用CXF代理.以上概述了其他人的解决方法.