Spring integration 在HttpComponents客户端HttpRequestFactory中配置特定的HTTPClient属性

Spring integration 在HttpComponents客户端HttpRequestFactory中配置特定的HTTPClient属性,spring-integration,connection-pooling,apache-httpclient-4.x,Spring Integration,Connection Pooling,Apache Httpclient 4.x,我正在使用spring与http出站网关集成,该网关使用HttpComponentClientHttpRequestFactory。我有以下异常NoHttpResponseException 2019-08-13 16:09:51,839 http-bio-8443-exec-439 ERROR LoggingHandler:184 - org.springframework.messaging.MessageHandlingException: HTTP request execution f

我正在使用spring与http出站网关集成,该网关使用HttpComponentClientHttpRequestFactory。我有以下异常NoHttpResponseException

2019-08-13 16:09:51,839 http-bio-8443-exec-439 ERROR LoggingHandler:184 - org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://my-service.com/my-service]; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://my-service.com/my-service": my-service:443 failed to respond; nested exception is org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:409)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
   Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://my-service.com/my-service": my-service.com:443 failed to respond; nested exception is org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:633)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:595)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:516)
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:382)
... 213 more
 Caused by: org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:143)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:261)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:165)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:91)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:619)
... 216 more
在四处搜索时,我发现了这个问题所在的陈旧连接,所以我想像文档中所说的那样驱逐它们

经典阻塞I/O模型的一个主要缺点是,只有在I/O操作中阻塞时,网络套接字才能对I/O事件作出反应。当连接被释放回管理器时,它可以保持活动状态,但是它无法监视套接字的状态并对任何I/O事件作出反应。如果连接在服务器端关闭,客户端连接将无法检测到连接状态的变化(并通过关闭其端的套接字做出适当的反应)

HttpClient试图通过测试 连接“过时”,已关闭,因此不再有效 在服务器端,在使用连接执行 HTTP请求。陈旧连接检查不是100%可靠。这个 唯一可行的解决方案,不涉及每个套接字一个线程 空闲连接的模型是一个专用的监视线程,用于退出 由于长时间的连接而被视为已过期的连接 不活动。监视器线程可以定期调用 ClientConnectionManager#closeExpiredConnections()方法关闭所有 过期的连接并从池中收回已关闭的连接。它可以 也可以选择调用ClientConnectionManager#closeIdleConnections() 方法关闭在给定时间内处于空闲状态的所有连接 一段时间


不幸的是,Spring抽象只提供了修改超时的功能,但我无法更改池配置或访问池管理器来完成它

一个选项是扩展HttpComponents客户端HttpRequestFactory,并添加从cron作业访问HttpClientConnectionManager的方法,以清除陈旧的连接,但您可能知道有一个更好的选项


是否有一个spring集成抽象,我可以使用apache的HTTPClient来清理http outboung网关上的过时连接?

spring集成目前没有,但如果您想有所贡献,我们很乐意添加它

不过,我不会使用每5秒唤醒一次的专用线程,我会使用SpringIntegration的内置任务调度器,它有一个可配置的时间表和过期的空闲时间

不过,看起来你不需要扩建工厂;您可以使用
factory.getHttpClient().getConnectionManager()
——虽然我认为这是不推荐使用的,但可能需要更新工厂以使用较新的API


但是,这是一个不同的故事;可能应该针对Spring框架本身提出一些问题。

谢谢Gary!由于不推荐使用的方法,我考虑了一个子类。我们如何才能不反对这种方法?我对贡献感兴趣,这是为了做到这一点而采取的步骤吗?这需要是对第一个使用新API替换/更新工厂的贡献。也许到期日也应该在那里。我建议第一步是在那边的GitHub上打开一个问题,以获得该团队的反馈——在问题中提及您感兴趣的贡献。
<int-http:outbound-gateway id="httpOutboundGateway" request-channel="requestServiceHttpChannel"
    reply-channel="responseServiceHttpChannel" url-expression="headers.serviceUrl" http-method="POST"
    expected-response-type="java.lang.String" charset="UTF-8" request-factory="httpOutboundRequestFactoryBean"
    message-converters="messageConverterList" header-mapper="headerMapperBean"/>

<bean id="httpOutboundRequestFactoryBean"
      class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
        <property name="readTimeout" value="${http.service.timeout.readResponse}"/>
        <property name="connectTimeout" value="${http.service.timeout.connection}"/>
    </bean>