REST控制器返回InputStreamResource时InputStream未释放问题咨询
Hey there! I totally get this frustration—resource leaks can be tricky to track down, especially with streaming responses in Spring. Let's break down why this happens and how to fix it properly.
Why the Leak Happens
The InputStreamResource class doesn't implement AutoCloseable, and Spring MVC's default message converters don't automatically close the underlying InputStream after sending the response. That means the stream from your GridFSDBFile stays open, tying up critical resources like database connections or file handles over time.
Solution 1: Use StreamingResponseBody (Recommended)
StreamingResponseBody is Spring's built-in solution for streaming responses, and it handles resource cleanup automatically. It’s purpose-built for this exact scenario, so it’s the cleanest fix. Here’s how to refactor your method:
@RequestMapping(value = "by-id/{attachmentId}", method = RequestMethod.GET) public ResponseEntity<StreamingResponseBody> attachmentById(@PathVariable("attachmentId") String attachmentId) { GridFSDBFile file = service.getAttachment(attachmentId); // ... your existing code to set respHeaders ... StreamingResponseBody responseBody = outputStream -> { // Use try-with-resources to auto-close the input stream once done try (InputStream inputStream = file.getInputStream()) { // Copy stream data (use Apache Commons IO for simplicity, or implement your own loop) org.apache.commons.io.IOUtils.copy(inputStream, outputStream); } catch (IOException e) { // Handle exceptions appropriately—throw a runtime exception or custom exception throw new RuntimeException("Failed to stream attachment content", e); } }; return new ResponseEntity<>(responseBody, respHeaders, HttpStatus.OK); }
- The
try-with-resourcesblock ensures theInputStreamfromGridFSDBFileis closed immediately after the data is copied. - Spring MVC takes care of closing the output stream once the response is fully sent to the client.
Solution 2: Custom Auto-Closable Resource (If You Must Use Resource)
If you have specific constraints requiring a Resource return type, you can create a custom implementation that handles stream closure. Here’s a quick example:
public class AutoClosingInputStreamResource extends InputStreamResource implements AutoCloseable { private final InputStream inputStream; public AutoClosingInputStreamResource(InputStream inputStream) { super(inputStream); this.inputStream = inputStream; } @Override public void close() throws IOException { inputStream.close(); } }
Then, you’d need to add a ResponseBodyAdvice or interceptor to call close() on the resource after the response is processed. This approach is more complex than using StreamingResponseBody, so only use it if you have no other option.
Key Takeaway
Stick with StreamingResponseBody for streaming file responses in Spring—it eliminates manual resource management and prevents leaks by design. It’ll keep your code clean and avoid those hard-to-debug resource exhaustion issues.
内容的提问来源于stack exchange,提问作者ASten

