Boost Spring Boot Performance with a Deflate Compression Filter

This article explains what Deflate compression is, why it improves performance, when to use it, and provides a step‑by‑step Spring Boot 3 implementation—including a custom filter, response wrapper, registration, testing, and optional GZIP configuration—to reduce response size and enhance user experience.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Boost Spring Boot Performance with a Deflate Compression Filter

1. Introduction

Application performance is crucial for user experience. Reducing the size of data transferred between server and client is an effective way to improve performance, and compression techniques play a key role. Spring Boot provides built‑in support for various compression methods.

1.1 What is Deflate compression?

Deflate is a lossless data compression algorithm that combines LZ77 and Huffman coding. In web applications it is commonly used to compress HTTP responses before they are sent to the client.

1.2 Why use Deflate compression?

Improved performance : Faster data transfer and lower latency, especially for users on slow or limited bandwidth connections.

Bandwidth savings : Reduces the amount of data transmitted, which is important for high‑traffic or heavy‑load services.

Better user experience : Faster response times lead to a smoother experience, particularly for mobile users or remote clients.

1.3 Application scenarios

Large response payloads : APIs returning large JSON or XML can benefit significantly from compression.

Static resources : Compressing HTML, CSS, JavaScript and other static files improves page load times.

Note: Compressing very small responses (under 2 KB) may degrade performance.

2. Practical implementation

2.1 Deflate filter

public class DeflateCompressionFilter implements Filter {
  private static final int MIN_RESPONSE_SIZE = 2 * 1024;
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resp = (HttpServletResponse) response;
    String acceptEncoding = req.getHeader("Accept-Encoding");
    if (acceptEncoding == null || !acceptEncoding.toLowerCase().contains("deflate")) {
      chain.doFilter(request, response);
      return;
    }
    DeflateResponseWrapper responseWrapper = new DeflateResponseWrapper(resp);
    chain.doFilter(request, responseWrapper);
    if (responseWrapper.getContentLength() > MIN_RESPONSE_SIZE) {
      resp.setHeader("Content-Encoding", "deflate");
      try (DeflaterOutputStream dos = new DeflaterOutputStream(resp.getOutputStream())) {
        dos.write(responseWrapper.getCapturedData());
      }
    } else {
      resp.getOutputStream().write(responseWrapper.getCapturedData());
    }
  }
}

2.2 Response wrapper

public class DeflateResponseWrapper extends HttpServletResponseWrapper {
  private final ByteArrayOutputStream capture = new ByteArrayOutputStream();
  private ServletOutputStream outputStream;
  private PrintWriter writer;
  public DeflateResponseWrapper(HttpServletResponse response) {
    super(response);
  }
  @Override
  public ServletOutputStream getOutputStream() {
    if (writer != null) {
      throw new IllegalStateException("Writer already in use");
    }
    if (outputStream == null) {
      outputStream = new ServletOutputStream() {
        @Override public void write(int b) throws IOException { capture.write(b); }
        @Override public void flush() throws IOException { capture.flush(); }
        @Override public void close() throws IOException { capture.close(); }
        @Override public boolean isReady() { return true; }
        @Override public void setWriteListener(WriteListener writeListener) {}
      };
    }
    return outputStream;
  }
  @Override
  public PrintWriter getWriter() {
    if (outputStream != null) {
      throw new IllegalStateException("OutputStream already in use");
    }
    if (writer == null) {
      writer = new PrintWriter(capture);
    }
    return writer;
  }
  public byte[] getCapturedData() { return capture.toByteArray(); }
  public int getContentLength() { return capture.size(); }
}

2.3 Registering the filter

@Bean
FilterRegistrationBean<DeflateCompressionFilter> deflateCompressionFilter() {
  FilterRegistrationBean<DeflateCompressionFilter> registrationBean = new FilterRegistrationBean<>();
  registrationBean.setFilter(new DeflateCompressionFilter());
  registrationBean.addUrlPatterns("/*");
  registrationBean.setName("DeflateCompressionFilter");
  registrationBean.setOrder(1);
  return registrationBean;
}

2.4 Testing

We expose a test endpoint that returns a large list of users:

@GetMapping("/data")
public List<User> getData() {
  List<User> data = new ArrayList<>();
  for (long i = 0; i < 10000; i++) {
    data.add(new User(i, "Name - " + i, new Random().nextInt(100)));
  }
  return data;
}
public record User(Long id, String name, Integer age) {}

When the request header Accept-Encoding is set to deflate, the response size is reduced by about 6.7 times compared with an uncompressed response, significantly improving performance and reducing bandwidth usage.

Note: GZIP is more widely supported and generally recommended; it can be enabled with the following Spring Boot configuration:

server:
  compression:
    enabled: true
    min-response-size: 1024
    mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml

The same custom filter can be adapted to use GZIPOutputStream instead of DeflaterOutputStream for gzip compression.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootDeflate compressionHTTP CompressionJava filter
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.