在系统A-> B-> C之间发送文件而不将整个文件存储在B中

时间:2015-12-07 19:11:54

标签: java spring spring-mvc

我有3个单独的弹簧网络应用程序

  • A 使用spring 4.x
  • B 使用spring 3.2.0
  • C 使用spring 4.x

B C 公开用于上传文件的REST控制器

  • A 读取文件并将其上传至 B
  • B 将请求发送至 C ,无需读取文件内容
  • 然后 C 对文件执行任何操作。

因此,流程将是 A-> B-> C

我的问题是 - 是否可以设置 B 以便 B 不会将整个文件存储在内存中,但会读取传入内容流并将其转发到 C

我设法做的是: 的 A

public void sendFileFromA() throws FileNotFoundException {
    final InputStream fis = new FileInputStream(new File("someFile"));
    final RequestCallback requestCallback = new RequestCallback() {
        @Override
        public void doWithRequest(final ClientHttpRequest request) throws IOException {
            request.getHeaders().add("Content-type", "application/octet-stream");
            IOUtils.copy(fis, request.getBody());
        }
    };
    final RestTemplate restTemplate = new RestTemplate();
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false);
    restTemplate.setRequestFactory(requestFactory);

    final HttpMessageConverterExtractor<String> responseExtractor = new HttpMessageConverterExtractor<>(
            String.class, restTemplate.getMessageConverters());
    restTemplate.execute("http://b_url/upload", HttpMethod.POST, requestCallback, responseExtractor);
}

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody String handleFileUpload(HttpServletRequest request) throws IOException {
    final ServletInputStream input = request.getInputStream();

    final RequestCallback requestCallback = new RequestCallback() {
        @Override
        public void doWithRequest(final ClientHttpRequest request) throws IOException {
            request.getHeaders().add("Content-type", "application/octet-stream");
            try (OutputStream body = request.getBody()) {
                IOUtils.copy(input, body);
            }
        }
    };
    final RestTemplate restTemplate = new RestTemplate();
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false);
    restTemplate.setRequestFactory(requestFactory);

    final HttpMessageConverterExtractor<String> responseExtractor = new HttpMessageConverterExtractor<>(
            String.class, restTemplate.getMessageConverters());
    restTemplate.execute("http://c_url/upload", HttpMethod.POST, requestCallback, responseExtractor);

    return "success";
}

C

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody String handleFileUpload(HttpServletRequest request) throws IOException {
    ServletInputStream input = request.getInputStream();

    try (BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream("zibiTest"))) {
        IOUtils.copy(input, output);
    }
    return "success";
}

我可以使用B轻松地将超过&gt; 10GB的文件从A复制到C.

使用这样的解决方案,我们可以尝试在传输时停止A,B和C应该收到有关错误的通知,但有时会发生错误消息未达到C - 它因套接字超时异常而关闭,知道为什么会这样,以及如何正确实施它?

这是一种有效的方法还是可以更好地处理?

2 个答案:

答案 0 :(得分:6)

我会尝试在C上设置比在B上更小的套接字超时。目前看起来两者都有一些默认值,所以如果A挂起,B和C几乎都会停止获取数据。两者都开始超时,也许它是竞争条件,它取决于首先超时的超时精度。

答案 1 :(得分:0)

你有没有想过Flume?从我所看到的,这里的挑战是不将它存储在B和文件中我认为它们可能很大。在这种情况下,为什么不使用Apache Flume的方式直接将文件流式传输到通道,然后再使用您的B接收器并将其转储到您的最终目的地&#34; C&#34;。无论文件大,这个拱都有帮助。

正如有人所说,&#34;如果我的知识仅限于您所看到的问题,我可能只是解决方案的媒介,而不是解决方案本身&#34;