Discover how to use Brotli compression in Spring Boot with Brotli4j. This beginner-friendly guide covers everything from setup to practical examples, ensuring your Spring Boot app performs optimally with Brotli compression.
1. Introduction
In modern web applications, compressing responses is essential for enhancing performance by reducing payload size and improving load times. We’ve previously covered Gzip compression in Spring Boot, which is widely used for similar purposes. If you’re interested in exploring Gzip compression, you can check out the following articles:
- How to Enable Gzip Compression in Spring Boot
- Conditional Gzip Compression in Spring Boot
- How to Decompress Gzip Requests in Spring Boot
- Sending and Handling Gzip Compressed Requests and Responses with RestTemplate in Spring Boot
While Gzip is a popular choice, Brotli is an advanced compression algorithm offering superior compression rates, making it a great alternative for web applications. In this article, we’ll dive into how you can use Brotli in your Spring Boot app with the help of the Brotli4j library. We’ll also cover what Brotli is and how to configure your application to send Brotli-compressed responses.
2. What is Brotli Compression?
Brotli is a modern lossless compression algorithm developed by Google, optimized for compressing web assets like HTML, CSS, and JavaScript. Brotli offers better compression ratios compared to Gzip, making it an excellent choice for reducing response sizes and improving loading times for users. Major browsers and web servers, including Apache and NGINX, support Brotli.
3. What is Brotli4j?
Brotli4j is a Java library that provides support for Brotli compression and decompression. It’s easy to integrate into Spring Boot applications and helps in sending Brotli-compressed responses to clients. This library supports Brotli’s various compression levels and can be used to compress or decompress data streams, files, or HTTP responses in Spring Boot applications.
4. Does Spring Boot Support Brotli Compression Out of the Box?
Spring Boot provides native support for Gzip compression, but it doesn’t have built-in support for Brotli compression as of now. However, we can leverage Brotli4j to manually configure Brotli compression in a Spring Boot application.
5. How to Send Brotli Compressed Responses in Spring Boot?
To implement Brotli compression in a Spring Boot application, we can use a filter to handle the compression process. The filter checks if the client supports Brotli compression by inspecting the Accept-Encoding
header and, if supported, compresses the response accordingly.
Let’s look at how to set up Brotli compression in a Spring Boot application using a filter.
Step 1: Add the Brotli4j Maven Dependency
First, you need to add the brotli4j dependency to your pom.xml
file. The latest version of the dependency can be obtained from here.
<dependency>
<groupId>com.aayushatharva.brotli4j</groupId>
<artifactId>brotli4j</artifactId>
<version>1.17.0</version>
</dependency>
application.propertiesThis library provides the necessary utilities to compress data using Brotli.
Step 2: Load Brotli4j in the Startup Class
In your main application class, ensure that the Brotli4j native library is loaded. You can do this by using the Brotli4jLoader.ensureAvailability()
method in the CommandLineRunner
interface.
import com.aayushatharva.brotli4j.Brotli4jLoader;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootBrotliCompressionApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(SpringBootBrotliCompressionApplication.class, args);
}
@Override
public void run(String... args) {
// Load the native library
Brotli4jLoader.ensureAvailability();
}
}
SpringBootBrotliCompressionApplication.javaThis ensures that Brotli4j is ready to be used for Brotli compression.
Step 3: Create a Simple Controller that returns Large Response
To test Brotli compression, let’s create a simple controller that returns a large string response. This will allow us to see the effect of compression more clearly.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BrotliController {
@GetMapping("/large-response")
public String getLargeResponse() {
return "Hello, World! ".repeat(1000000);
}
}
BrotliController.javaThis endpoint returns a large text response that will be compressed using Brotli.
Step 4: Using Filters for Brotli Compression in Spring Boot
Filters in Spring Boot can intercept requests and responses before they are handled by the controller. Let’s create a custom filter that compresses the response using Brotli when the client supports it.
a. Create a Brotli Compression Filter
The BrotliCompressionFilter
is a custom filter that checks if the client supports Brotli compression by inspecting the Accept-Encoding
HTTP header. If the client supports Brotli (i.e., the header contains “br”), the filter captures the response, compresses it using Brotli, and then sends the compressed response back to the client.
import com.aayushatharva.brotli4j.encoder.Encoder;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Order(1)
@Component
public class BrotliCompressionFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Check if Brotli compression is supported by the client
String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
if (acceptEncoding != null && acceptEncoding.contains("br")) {
System.out.println("Brotli compression request received");
// Use a custom wrapper to capture the response content
BrotliHttpServletResponseWrapper wrappedResponse = new BrotliHttpServletResponseWrapper(httpResponse);
// Proceed with the filter chain
chain.doFilter(request, wrappedResponse);
System.out.println("Initiating response compression");
// Compress the captured response content with Brotli
byte[] uncompressedData = wrappedResponse.getResponseData();
byte[] brotliCompressedData = Encoder.compress(uncompressedData);
// Modify response headers
httpResponse.setHeader("Content-Encoding", "br");
httpResponse.setContentLength(brotliCompressedData.length);
// Write the compressed response back to the output stream
httpResponse.getOutputStream().write(brotliCompressedData);
} else {
// Proceed without Brotli compression if not supported
chain.doFilter(request, response);
}
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
BrotliCompressionFilter.javaIn Spring Boot, filters are automatically registered if annotated with @Component
. The @Order(1)
annotation specifies the order in which the filter is applied. In this case, it will run before any other filters.
b. Create the BrotliHttpServletResponseWrapper
The BrotliHttpServletResponseWrapper
class is a custom implementation of HttpServletResponseWrapper
. It acts as a buffer to capture the response content before it’s written to the output stream. This is essential for applying compression after the response has been generated.
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
public class BrotliHttpServletResponseWrapper extends HttpServletResponseWrapper {
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private final PrintWriter printWriter = new PrintWriter(outputStream);
public BrotliHttpServletResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public boolean isReady() {
// Indicate whether the stream is ready to be written to.
return true; // Changed to true for better compatibility
}
@Override
public void setWriteListener(WriteListener writeListener) {
// No-op for synchronous processing
}
@Override
public void write(int b) throws IOException {
outputStream.write(b); // Write data to buffer
}
};
}
@Override
public PrintWriter getWriter() {
return printWriter; // Use PrintWriter to capture text data
}
public byte[] getResponseData() {
printWriter.flush(); // Ensure all data is written to the buffer
return outputStream.toByteArray(); // Return buffered response data
}
}
BrotliHttpServletResponseWrapper.javaIt enables capturing the uncompressed response content, which can be compressed and sent to the client later. Without this wrapper, the response would be written directly to the output stream, making it impossible to compress the data after it’s been written.
6. Testing Our Spring Boot Application with Brotli Compression
To test the Brotli compression, start your Spring Boot application and make a GET request to the /large-response
endpoint. You can verify the response time, response size, and the Content-Encoding
header using Postman.
- Open Postman and create a new GET request to
http://localhost:8080/large-response
. - In the request headers, add
Accept-Encoding
with the valuebr
to indicate that the client supports Brotli compression. - Send the request.
After you receive the response, check the following:
- Response Time: The duration it took to complete the request.
- Response Size: The size of the response payload.
- Content-Encoding: This should be set to
br
if Brotli compression has been successfully applied.
Important Note on Postman Version
Ensure you are using Postman version 11.8 or higher, as this version provides detailed insights about compressed and uncompressed size breakdowns.
Additionally, if you want to test the same using a browser’s network tab, you can refer to a similar approach mentioned here.
Output:
Compare response sizes in screenshots with and without Brotli compression enabled. Verify the presence of the ‘Content-Encoding: br’ header in the ‘Response Headers’ section to confirm successful compression.
7. Why You Need Brotli4jLoader.ensureAvailability()?
The Brotli4jLoader.ensureAvailability()
method is crucial for loading the native Brotli libraries in your application. If this method is not called, you may encounter the java.lang.UnsatisfiedLinkError
error during runtime. This error indicates that the necessary native code for Brotli compression is not available, leading to failure in performing compression operations.
Output:
8. Setting Brotli Compression Levels
You can adjust the Brotli compression level using the Encoder.Parameters.setQuality()
method, which can be specified as a parameter in the Encoder.compress()
method. Here’s how to implement it:
....
byte[] brotliCompressedData = Encoder.compress(uncompressedData, Encoder.Parameters.DEFAULT.setQuality(11));
....
BrotliCompressionFilter.javaThe compression level can range from 0
to 11
, where lower levels provide faster response times but with less compression, while higher levels achieve better compression at the cost of slower response times. The acceptable values are from 0
to 11
, or -1
for default compression settings.
If you provide a value outside this range, you will encounter an IllegalArgumentException
with the message: quality should be in range [0, 11], or -1
. This ensures that the compression process only uses valid quality levels.
9. Source Code
The complete source code of the above example can be found here.
10. Things to Consider
Here are some important considerations to keep in mind while working with Brotli compression in Spring Boot:
- Browser Support: Ensure that clients (browsers or other services) requesting resources support Brotli compression. Most modern browsers, like Chrome, Firefox, and Edge, support Brotli, but it’s good to check compatibility with your target audience.
- Performance Impact: Brotli compression can be more CPU-intensive than other algorithms (like Gzip) due to its complex compression algorithm. Monitor the performance impact on your server, especially under heavy load, to ensure that compression does not lead to significant latency.
- Compression Levels: Brotli allows you to configure different compression levels (0-11). Higher levels provide better compression ratios but at the cost of increased CPU usage. Choose an appropriate compression level based on your application’s needs and server capabilities.
- Testing and Validation: Use tools like Postman or browser developer tools to verify the
Content-Encoding
header and check the response size. - Fallback Mechanism: Implement a fallback mechanism for clients that do not support Brotli compression. This could involve checking the
Accept-Encoding
header and serving uncompressed or Gzip-compressed responses as a backup. - Static Content: If your application serves a lot of static content (e.g., images, CSS, JavaScript), consider pre-compressing these assets with Brotli and serving them directly. This can significantly reduce the load time for static resources.
- Memory Usage: Brotli’s compression may require more memory than other algorithms, particularly when using higher compression levels. Keep an eye on memory usage to prevent potential out-of-memory errors.
11. FAQs
How do I know if my client supports Brotli compression?
Clients indicate support for Brotli compression by including br
in the Accept-Encoding
header. Your Spring Boot application can check this header to decide whether to compress responses using Brotli.
Can Brotli compression slow down my application?
Higher compression levels (closer to 11) can result in slower compression times, which may increase response times. If performance is a concern, you can opt for a lower compression level for quicker response times.
What happens if Brotli is not enabled in my Spring Boot application?
If Brotli is not enabled or supported by the client, the response will not be compressed with Brotli, and Spring Boot will send the uncompressed response or use Gzip if it’s enabled as a fallback.
What does Brotli compression quality level mean, and how do I choose the right one?
The Brotli compression quality level, ranging from 0 to 11, determines the tradeoff between compression speed and compression ratio. Lower levels mean quicker responses but less compression, while higher levels provide better compression but take longer to process.
How can I verify if Brotli compression is working in my Spring Boot app?
You can verify Brotli compression by checking the Content-Encoding
header in the response. If Brotli is applied, it should show br
. You can also compare the response sizes to see the effect of compression.
12. Conclusion
In conclusion, Brotli compression significantly reduce response sizes in your applications, leading to faster load times and improved performance. By integrating Brotli4j and configuring a simple filter, you can enable Brotli compression in Spring Boot seamlessly for large responses, ensuring optimal user experience. While Brotli provides excellent compression rates, it’s essential to balance the compression level with response speed based on your application’s needs. With the setup discussed in this article, you can start leveraging Brotli compression effectively in your Spring Boot app.
13. Learn More
Interested in learning more?
Checkout our blog on How to Print SQL Queries with Values in Spring Boot with Spring Data JPA
Add a Comment