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.
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/xmlThe same custom filter can be adapted to use GZIPOutputStream instead of DeflaterOutputStream for gzip compression.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
