Affects: Spring-web-5.2.13.RELEASE

org.springframework.http.converter.ResourceHttpMessageConverter#writeContent use StreamUtils.copy() to realize local file resource copy. However StreamUtils.copy() inner use linux write() api that needs twice DMA copy and twice CPU copy. I'd like to use sendfile instead of it.

My suggestion is like that:

public long writeTo(GatheringByteChannel destChannel, long offset, int length) throws IOException {
        long newSize = Math.min(channel.size(), end) - start;
        int oldSize = sizeInBytes();

        long position = start + offset;
        int count = Math.min(length, oldSize);
        final long bytesTransferred;
        if (destChannel instanceof TransportLayer) {
            TransportLayer tl = (TransportLayer) destChannel;
            bytesTransferred = tl.transferFrom(channel, position, count);
        } else {
            bytesTransferred = channel.transferTo(position, count, destChannel);
        }
        return bytesTransferred;
    }

Comment From: poutsma

We would love to use zero-copy (aka sendfile) in Servlet environments, but unfortunately the Servlet API does not give us access to any kind of Channel, just input and output streams. So as far as I know, sendFile can't be used.

Note that we do use zero-copy in WebFlux, see ResourceHttpMessageWriter.

Comment From: asasas234

@kyangcmXF This is actually possible, I implemented it last year, but I only remember the approximate steps. First, make sure that the server you are using is tomcat, and then call request.setAttribute in the Spring Mvc Controller to specify the two parameters that tomcat supports sendfile (specifically, you need to check the documentation), and then the code will go to tomcat to support sendfile In a class of , you can debug it. In short, this will transfer the logic of sending files, the total spring mvc control to tomcat to control, all we have to do is pass parameters to open sendfile and file paths and the like.