2015-12-07 8 views
14

にファイル全体を記憶せず、私は3つの別々のスプリングのWebアプリケーションを有する送信ファイルA-> B-> C B

  • がばね4.xの
  • Bはスプリング3.2を使用して使用.0
  • Cバネ4.xを使用

BCは、ファイルの内容を読むために必要なしCにリクエストを送信するファイルのアップロードのためのRESTコントローラが

  • Bにファイルやアップロード、それを読み込み
  • Bを公開します
  • 、次には、ファイルで必要なものは何でも行います。

ので、流れは以下のようになりA-> B-> C

私の質問は - それは、このような方法でセットアップBすることが可能であるので、Bは全体保管しないであろうとファイルをメモリに読み込みますが、着信ストリームを読み取ってCに転送しますか?

私は何を管理することです:

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); 
} 

B

@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"; 
} 

私は10GB以上のファイルをAからCに簡単にコピーすることができます。

このような解決策では、転送中にAを停止しようとすると、BとCにエラーが通知されるはずですが、メッセージがCに届かない - ソケットタイムアウト例外、これがどうして起こるのか、またそれを正しく実装する方法については、クローズしてしまいますか?

これは有効なアプローチですか、それとも改善されますか?

+1

あなたがロードする必要があるファイルを読むためには、「私の知識だけ見て問題に限定されている場合は、私が唯一の解決策のための媒体ではなくソリューションそのものであってもよいです」メモリへ。あなたがBでファイルを受け取ったら、そのファイルはすでにメモリに入っています。 – reos

+0

ファイルをBの1つのスレッドのパイプに書き込み、次に別のスレッド(Bの場合もある)で読み取ってからCに送信します。java.nio.channels.Pipeを参照してください。 Cは受信しようとしているデータの量(httpヘッダー)を知りたいかもしれません。 –

+1

@reosよく、ファイルの一部を読んだり、何かをしたりして、次の部分を読むことができます。 – Henry

答えて

6

私は、CであなたがBよりも小さいソケットタイムアウトを設定しようとしています。現在、両方のいくつかのデフォルト値があるようですので、Aがハングすると、BとCはデータをほぼ同時に取得しなくなります。どちらもタイムアウトを開始し、競合状態である可能性があります。タイムアウトの精度に依存します。

+1

最初の(2つの)サブクエリであなたのテイクは何ですか?私にとってはBが転送中にファイル全体を格納していないようで、結局彼はBのコントローラで 'ServletInputStream'を得て、バイト配列ではないようです。 –

0

Flumeについて考えましたか?私が見ることができるから、ここでの挑戦はそれをBとファイルに保存しないことです。ファイルが大きいと思われます。そのような場合には、Apache Flumeの方法でファイルを直接チャンネルにストリーミングしてからシンクに送り、Bを最終的な宛先「C」にダンプしてみてください。ファイルは大容量ですが、このアーチが役立ちます。誰かが述べたように

関連する問題