我使用camel-cxfrs组件来映射一个简单的REST GET操作,该操作返回从外部资源中提取的数据。一切都很好,直到我决定启用" streamCache"因为要返回的数据有时会非常大(最多50MB),我们不想将其加载到内存中,否则我们会在同时执行多个请求时耗尽内存! 所以我配置了一个DefaultStreamCachingStrategy来定义何时将数据流传输到tmp文件(例如,大于1MB的数据)。
这工作正常,一旦我的数据从外部资源(数据库中的blob !!)获取,它就会流回到调用者,并且因为数据大于阈值,Camel正在将我的输入流转换为一个FileInputStreamCache,这很好......直到响应准备好通过CXF组件返回给调用者!因为消息传递给CXF组件,所以不再需要Camel交换(输出消息留下Camel上下文),因此在内容完全返回到REST之前,Camel删除创建的tmp文件(由其TempFileManager实现)客户端!
这导致IOException,因为CXF组件正在尝试从输入流(刚刚被Camel关闭)读取数据到http客户端。
任何想法如何解决这个问题?我需要保持tmp文件打开,直到所有响应数据都可以发送回REST客户端。但是一旦发送响应,就必须关闭并删除。
这里我的Camel上下文和一些bean是如何定义的(不显示所有内容):
<!-- ... -->
<cxf:rsServer address="/path" id="rsServer">
<cxf:providers>
<!-- ... -->
</cxf:providers>
<cxf:serviceBeans>
<ref bean="resourcesEndpoint"/>
</cxf:serviceBeans>
<!-- ... -->
</cxf:rsServer>
<!-- ... -->
<bean class="org.apache.camel.impl.DefaultStreamCachingStrategy" id="streamStrategy">
<property name="enabled" value="true"/>
<property name="bufferSize" value="512000"/>
<property name="spoolThreshold" value="512000"/>
<property name="spoolUsedHeapMemoryThreshold" value="8}"/>
<property name="spoolUsedHeapMemoryLimit" value="Max"/>
<property name="removeSpoolDirectoryWhenStopping" value="true"/>
<property name="anySpoolRules" value="true"/>
</bean>
<!-- ... -->
<camelContext id="context" streamCache="true" trace="false" useBreadcrumb="true" useMDCLogging="true" xmlns="http://camel.apache.org/schema/spring">
<!-- ... -->
<route id="mainRoute" >
<from id="fromCXFEndpoint" uri="cxfrs:bean:rsServer?bindingStyle=SimpleConsumer"/>
<recipientList id="_recipientList1">
<simple>direct:${header.operationName}</simple>
</recipientList>
</route>
<route id="downloadDataRoute" >
<from id="fromDownloadDataCXF" uri="direct:downloadData"/>
<!-- ... -->
<!-- Performing data fetching... not showing everything here! -->
<!-- ... -->
</route>
</camelContext>
接下来,用于映射REST请求的端点类:
@Path("/resources")
@Component
@Service
public class ResourcesEndpoint {
@GET
@Path("/data/{guid}")
@Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM})
public StreamingOutput downloadData(@PathParam("guid") String guid) {
return null;
}
}