RESTJava客户端API:在分配另一个连接之前释放连接

RESTJava客户端API:在分配另一个连接之前释放连接,java,rest,jax-rs,Java,Rest,Jax Rs,我正在使用以下测试代码调用REST服务: public class TestRESTServices { private static final String BASE_URL = "http://localhost/ma.ge.persistence-1.0/rest/reference"; private static URI uri = UriBuilder.fromUri(BASE_URL).port(8080).build(); private static

我正在使用以下测试代码调用REST服务:

public class TestRESTServices {
    private static final String BASE_URL = "http://localhost/ma.ge.persistence-1.0/rest/reference";
    private static URI uri = UriBuilder.fromUri(BASE_URL).port(8080).build();
    private static Client client = ClientBuilder.newClient();

    @Test
    public void createAndDeleteAReference() {

        Reference r = ReferenceFactory.createReference("Maz",
                "dummy", 1.7);
        Response response = client.target(uri).request().post(Entity.entity(r, MediaType.APPLICATION_JSON));
        assertEquals(Response.Status.CREATED, response.getStatusInfo());

        URI referenceURI = response.getLocation();

        // Get the posted reference
        response = client.target(referenceURI).request().get();

        Reference retreivedRef = response.readEntity(Reference.class);
        assertEquals(Response.Status.OK, response.getStatusInfo());
        assertEquals(retreivedRef.getName(), r.getName());

    }
但我得到了以下错误:

javax.ws.rs.ProcessingException:无法调用请求 位于org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:287) 位于org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:407) 位于org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.get(ClientInvocationBuilder.java:159) 在ma.gesto.persistence.TestRESTServices.createAndDeleteAReference(TestRESTServices.java:34) 在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处 在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)中 在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)中 位于java.lang.reflect.Method.invoke(Method.java:606) 位于org.junit.runners.model.FrameworkMethod$1.runReflectVeCall(FrameworkMethod.java:47) 位于org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 位于org.junit.runners.model.FrameworkMethod.invokeeexplosive(FrameworkMethod.java:44) 位于org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 位于org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 位于org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 位于org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 位于org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 位于org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 位于org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 访问org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 位于org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 位于org.junit.runners.ParentRunner.run(ParentRunner.java:309) 位于org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 位于org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 位于org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) 位于org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) 位于org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 位于org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 原因:java.lang.IllegalStateException:BasicClient ConnManager的使用无效:连接仍已分配。 在分配另一个连接之前,请确保释放该连接。 位于org.apache.http.impl.conn.BasicClientConnectionManager.getConnection(BasicClientConnectionManager.java:162) 位于org.apache.http.impl.conn.BasicClientConnectionManager$1.getConnection(BasicClientConnectionManager.java:139) 位于org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:456) 位于org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) 位于org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805) 位于org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:283) ... 26多


客户端
界面表示外部资源。因此,在静态变量中创建并存储一个变量是一个严重的错误。这是错误的:

private static Client client = ClientBuilder.newClient();
这对于单元测试来说是可以的:

private Client client;

@Before
public void setUp() {
    this.client = ClientBuilder.newClient();
}

@After
public void tearDown() {
    this.client.close();
}
在普通代码中,您可能希望将
客户机
用法包装为
使用资源进行尝试
尝试..最后

Client client = ClientBuilder.newClient();
try {
    // use the client to make requests
} finally {
    client.close();
}

理想情况下,有一种方法可以管理一个
客户端
实例池以供重用。

您还需要关闭响应以释放连接。 请参见此处的说明:

但是客户端的文档中包含:“客户端是管理客户端通信基础设施的重量级对象。初始化和处理客户端实例可能是一项相当昂贵的操作。因此建议在应用程序中只构造少量客户端实例。”@snorbi Yes,这就是为什么理想情况下您希望将它们管理在可重用客户机实例池中的原因,正如我回答的最后一句所说。池分配逻辑将检测断开连接的客户端实例(通常通过拦截异常),并用新实例替换它们。我想到了两种特别适用于资源池的设计模式:和。