Java RestTemplate:有没有办法保护jvm不受巨大响应大小的影响?

Java RestTemplate:有没有办法保护jvm不受巨大响应大小的影响?,java,spring,resttemplate,Java,Spring,Resttemplate,当使用RestTemplate与外部服务对话时,我在应用程序中不止一次看到OutOfMemory错误,因为服务流中有大量的数据(由于他们这方面的实现不好,如果出现错误,他们会在数组的每个元素中发回大的StackTrace,这些元素通常包含几千个)。它以大约6gb的数据结束,由jackson在我们的应用程序中序列化,并完全爆炸了jvm的Xmx 我环顾四周,但似乎没有任何方法可以防止这种情况,即当流式响应超过给定大小时中止请求 有解决办法吗?我们正在使用apache的httpcomponents h

当使用RestTemplate与外部服务对话时,我在应用程序中不止一次看到OutOfMemory错误,因为服务流中有大量的数据(由于他们这方面的实现不好,如果出现错误,他们会在数组的每个元素中发回大的StackTrace,这些元素通常包含几千个)。它以大约6gb的数据结束,由jackson在我们的应用程序中序列化,并完全爆炸了jvm的Xmx

我环顾四周,但似乎没有任何方法可以防止这种情况,即当流式响应超过给定大小时中止请求

有解决办法吗?我们正在使用apache的httpcomponents httpclient 4.5.5,但任何其他底层实现都是可以接受的


除了RestTemplates,还欢迎为Spring的反应式WebClient提供解决方案。

这必须在底层HTTP客户端库中实施(Spring支持不同的客户端,如JDK客户端、apache客户端、okHTTP..)

在这里,您讨论的是ApacheHttpComponent,您是否检查了这个
HttpEntity.getContent()
? 它实际上返回一个InputStream,您可以自己读取并确定何时超过了该大小


对于记录,这里是最终的解决方案。问题在于使用分页(通过弹性搜索滚动api)加载可能非常大的对象列表


我知道在httpclient 4.3中有一个选项,但它被弃用了,我可以找到替代品。非常有趣:“内容是从流接收的,或者是动态生成的。”这肯定可以做到,我要试一试。很好,让我知道,所以我猜这个解决方案是可行的,但太麻烦了,我放弃了。不可能使用spring的
RestTemplate
来获取
HttpEntity
,因此所有当前bean/测试/逻辑都需要重新处理。实际上,我已经找到了http组件4.3+的新的
最大行长度
:它位于
org.apache.http.config.MessageConstraints
中,用于
org.apache.http.config.ConnectionConfig
。它确实可以工作,但具有完全不可用的行为:如果响应大小超过最大设置,则不会引发异常,相反,restTemplate返回空元素。但是您可以使用
restTemplate
加载inputstream。看看这个最重要的部分是
ResponseExtractor
ResponseExtractor<Car[]> responseExtractor = responseEntity -> {
    long pageContentLengthInBytes = responseEntity.getHeaders().getContentLength();
    long presumableFreeMemoryInBytes = this.getAvailableFreeMemoryAmount();

    if (presumableFreeMemoryInBytes - TWENTY_MEGABYTES < pageContentLengthInBytes) {
        log.error("Not enough memory to store the page ({} avaiable, content-length={}, trashing it", presumableFreeMemoryInBytes, pageContentLengthInBytes);
        responseEntity.close();
        return null;
    }
    return objectMapper.readValue(responseEntity.getBody(), Car[].class);
};

Car[] responseEntities = this.restTemplate.execute(uri, HttpMethod.GET, null, responseExtractor);
   /**
     * Returns the current amount of memory which may be allocated until an out-of-memory error occurs.
     * see https://stackoverflow.com/a/12807848/8836232
     */
    private long getAvailableFreeMemoryAmount() {
        long allocatedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
        return Runtime.getRuntime().maxMemory() - allocatedMemory;
    }