0 Tage Serie
java / intermediate
Snippet

Speicherarme Übertragung großer Dateien via StreamingResponseBody

Das vollständige Laden riesiger Datensätze in den Arbeitsspeicher führt zu OutOfMemoryError-Abstürzen. Mit StreamingResponseBody schreibt Spring MVC Daten blockweise über einen asynchronen Worker-Thread direkt in den HTTP-OutputStream des Clients, wodurch der Heap-Verbrauch konstant bleibt.

snippet.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@RestController
@RequestMapping("/export")
public class DataExportController {
private final LargeDatasetService datasetService;
public DataExportController(LargeDatasetService datasetService) {
this.datasetService = datasetService;
}
@GetMapping("/records")
public ResponseEntity<StreamingResponseBody> streamExport() {
StreamingResponseBody stream = outputStream -> {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream))) {
datasetService.streamRecords(record -> {
writer.write(record.toCsvLine());
writer.newLine();
});
writer.flush();
}
};
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=export.csv")
.contentType(MediaType.TEXT_PLAIN)
.body(stream);
}
}
spring
Erklärung
1
StreamingResponseBody stream = outputStream -> { ... };
Definiert einen funktionalen Callback, den Spring asynchron mit direktem Zugriff auf den Client-OutputStream ausführt.
2
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream)))
Ummantelt den Rohdaten-Stream mit einem gepufferten Writer für effiziente Textausgabe.
3
datasetService.streamRecords(record -> { ... });
Verarbeitet Datensätze zeilenweise aus der Persistenzschicht, ohne die gesamte Liste im RAM zu halten.
4
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=export.csv")
Weist den Browser an, den eingehenden Bytestrom als CSV-Dateidownload zu behandeln.