Resteasy客户端在方法抛出异常后保持连接分配

时间:2016-10-31 13:18:19

标签: java web-services resteasy

我目前正在使用TJWSEmbeddedJaxrsServer来帮助我完成RESTful API测试(使用Resteasy创建)并且它可以很好地工作。 但是,当任何被调用的方法抛出异常时,就会出现问题:Reasteasy Client变为"丢失"仍然保持连接,不允许其他测试方法调用RESTful服务。即使您实现了可以解包异常并在嵌入式服务器中使用它的提供程序,也会发生这种情况。

有人可以帮助我吗?

要模拟问题,实际上很简单:

  1. https://github.com/mp911de/rest-api-test
  2. 下载Mark Paluch提供的样本
  3. 将测试类更改为:
  4. 公共类InMemoryRestTest {

    @Path("/myresource")
    public static class MyResource {
    
        @POST
        @Consumes(MediaType.TEXT_PLAIN)
        @Produces(MediaType.APPLICATION_XML)
        public MyModel createMyModel(int number) throws Exception {
            // supose this is a Business exception
            throw new Exception("Test");
        }
    
    }
    
    public static MyResource sut = new MyResource();
    public static InMemoryRestServer server;
    
    @BeforeClass
    public static void beforeClass() throws Exception {
        server = InMemoryRestServer.create(sut);
    }
    
    @AfterClass
    public static void afterClass() throws Exception {
        server.close();
    }
    
    @Test
    public void postSimpleBody() throws Exception {
        // This one throws the "Exception" exception and passes     
        Response response = server.newRequest("/myresource").request().buildPost(Entity.text("42")).invoke();
        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
    }
    
    @Test
    public void postAnother() throws Exception {
        // This one fails with "Invalid use of BasicClientConnManager: connection still allocated."
        Response response = server.newRequest("/myresource").request().buildPost(Entity.text("20")).invoke();
        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
    }
    

    }

    瞧!当测试" postAnother()"运行,将发生以下错误:

    javax.ws.rs.ProcessingException: Unable to invoke request
        at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:287)
        at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:407)
        at biz.paluch.rest.test.InMemoryRestTest.postSimpleBody(InMemoryRestTest.java:51)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
    Caused by: java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
    Make sure to release the connection before allocating another one.
        at org.apache.http.impl.conn.BasicClientConnectionManager.getConnection(BasicClientConnectionManager.java:162)
        at org.apache.http.impl.conn.BasicClientConnectionManager$1.getConnection(BasicClientConnectionManager.java:139)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:456)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
        at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:283)
        ... 27 more
    

3 个答案:

答案 0 :(得分:3)

您需要配置ResteasyClientBuilder以使用连接池。以下列方式修改InMemoryRestServer类的withDefaults()方法

//this.resteasyClient = new ResteasyrestEasyClientBuilder().build();
ResteasyrestEasyClientBuilder restEasyClientBuilder = new ResteasyrestEasyClientBuilder();
restEasyClientBuilder = restEasyClientBuilder.connectionPoolSize(20);
this.resteasyClient = restEasyClientBuilder.build();

这样两个测试用例都应该无异常运行(两者似乎都抛出了AssertionError)

答案 1 :(得分:3)

默认的ResteasyClientBuilder不使用连接池,这意味着您一次只能有一个并行连接。 因此,您必须确保关闭响应(即response.close())以释放(仅)连接。

请参阅此处的响应实施: https://github.com/resteasy/Resteasy/blob/master/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ClientResponse.java

public void close()
   {
      if (isClosed()) return;
      try {
         isClosed = true;
         releaseConnection(); // <= HERE!
      }
      catch (Exception e) {
         throw new ProcessingException(e);
      }
   }

所以以下内容应该可以解决您的问题:

@Test
public void postBody() throws Exception {          
    Response response = null;
    try {
        response = server.newRequest("...").request().buildPost(Entity.text("...")).invoke();           
    } finally {
        response.close();
    }   
}

此致

伯纳德。

答案 2 :(得分:0)

在Java SE 7和更高版本中,更干净的方法是对资源使用try。示例片段如下:

try(response = server.newRequest("...").request().buildPost(Entity.text("...")).invoke())
{ 
   /* response handling logic */ 
}