此 JAX-WS 客户机调用线程是否安全?

由于 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");
}

我班上某处的电话:

myPort.someFunctionCall(requestContext, "someValue");

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


答案 1

根据 CXF 常见问题解答

JAX-WS 客户机代理线程安全吗?

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

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

  • 使用 - 根据 JAX-WS 规范,请求上下文是每个实例。因此,在那里设置的任何内容都会影响其他线程上的请求。使用 CXF,您可以执行以下操作:((BindingProvider)proxy).getRequestContext()

    ((BindingProvider)proxy).getRequestContext().put("thread.local.request.context","true");
    

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

  • 导管上的设置 - 如果您使用代码或配置直接操作导管(例如设置TLS设置或类似设置),则这些设置不是线程安全的。管道是按实例计算的,因此这些设置将共享。此外,如果使用故障转移功能和负载平衡功能,则会动态更换管道。因此,在导管上设置的设置在用于设置螺纹之前可能会丢失。

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

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

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


答案 2

一般来说,不可以。

根据 CXF 常见问题解答 http://cxf.apache.org/faq.html#FAQ-AreJAX-WSclientproxiesthreadsafe?

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

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

有关例外列表,请参阅常见问题解答。


推荐