在多线程环境中重用 JAX RS 客户端(带 resteasy)

2022-01-21 00:00:00 multithreading java jax-rs jersey resteasy

根据文档,

客户端是管理客户端的重量级对象通信基础设施.初始化和处置客户端实例可能是一个相当昂贵的操作.因此是建议在应用."

"Clients are heavy-weight objects that manage the client-side communication infrastructure. Initialization as well as disposal of a Client instance may be a rather expensive operation. It is therefore advised to construct only a small number of Client instances in the application. "

好的,我正在尝试将 Client 本身和 WebTarget 实例缓存在静态变量中,在多线程环境中调用 someMethod():

Ok, I'm trying to cache Client itself and WebTarget instances in a static variable, the someMethod() is invoked in multi-threaded environment:

private static Client client = ClientBuilder.newClient();
private static WebTarget webTarget = client.target("someBaseUrl");
...
public static String someMethod(String arg1, String arg2)
{
    WebTarget target = entrTarget.queryParam("arg1", arg1).queryParam("arg2", arg2);
    Response response = target.request().get();
    final String result = response.readEntity(String.class);
    response.close();
    return result;
}

但有时(并非总是)我会遇到异常:

But sometimes (not always) I'm get an exception:

BasicClientConnManager 使用无效:连接仍然分配.确保在分配另一个连接之前释放连接.

Invalid use of BasicClientConnManager: connection still allocated. Make sure to release the connection before allocating another one.

如何正确重用/缓存 Client/WebTarget?可以使用 JAX RS 客户端 API 吗?或者我必须使用一些特定于框架的功能(resteasy/jersey)你能提供一些示例或文档吗?

How can Client/WebTarget be reused/cached correctly? Is it possible with JAX RS Client API? Or I have to use some framework-specific features (resteasy/jersey) Could you provide some example or documentation?

推荐答案

你的实现不是线程安全的.当两个线程同时访问 someMethod 时,它们共享相同的 Client 并且一个线程将尝试在第一个请求未完成时发出第二个请求.

Your implementation is not thread-safe. When two threads access someMethod at the same time they are sharing the same Client and one will try to make a second request while the first one is not finished.

你有两个选择:

  • 手动同步对ClientWebTarget的访问.
  • 让容器通过使用 @javax.ejb.Singleton 注释封闭类型来管理并发,这保证了线程安全.(参见 EJB 规范)
  • Synchronize the access to the Client and WebTarget manually.
  • Let the container manage concurrency by annotating the enclosing type with @javax.ejb.Singleton which guarantees thread safety. (see chapter 4.8.5 of the EJB specification)

如果 someMethod 在容器管理的环境中,我会使用第二种方法.

If someMethod in a container managed environment I would use the second approach.

相关文章