《Spring Boot 3实战案例合集》现已囊括超过100篇精选实战文章,并且此合集承诺将永久持续更新,为您带来最前沿的技术资讯与实践经验。欢迎积极订阅,享受不断升级的知识盛宴!订阅用户将特别获赠合集内所有文章的最终版MD文档(详尽学习笔记),以及完整的项目源码,助您在学习道路上畅通无阻。
🎉🎉我们精心打造的《Spring Boot 3实战案例锦集》PDF电子书现已正式完成,目前已经有104个案例,后续还将继续更新。文末有电子书目录。
💪💪永久更新承诺:
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。随着Spring相关技术的更新升级,我们的电子书也将持续更新,确保您始终掌握最前沿、最实用的技术知识。
💌💌如何获取:
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.2.5
1. 简介
一个应用的性能是决定用户体验好坏的关键因素。提高性能的最有效方法之一是减少服务器与客户端之间传输的数据大小。这正是压缩技术发挥作用的地方。Spring Boot 提供了对各种压缩技术的内置支持,以优化数据传输。
在本篇文章中,我们将探讨Deflate压缩,包括它为什么重要、何时使用它以及如何在Spring Boot应用程序中实现它。通过本篇文章你将清楚地了解如何使用Deflate压缩来优化应用程序的性能。
1.1 什么是Deflate压缩?
Deflate是一种无损数据压缩算法,它结合了LZ77算法和霍夫曼编码来减小数据的大小。在Web应用程序中,Deflate被广泛用于在向客户端发送HTTP响应之前对其进行压缩。
当客户端(例如浏览器或API使用者)从服务器请求数据时,服务器可以使用Deflate对响应进行压缩,从而减小通过网络传输的数据大小。客户端在接收到数据后进行解压缩。
1.2 为什么使用Deflate压缩?
提高性能
网络上的数据传输速度更快。延迟降低,特别是对于使用慢速或带宽有限的连接的用户而言。
节省带宽
压缩减少了通过网络发送的数据量,这对于流量高或负载大的应用程序(例如,JSON或XML响应)非常重要。
提升用户体验
更快的响应时间带来更好的用户体验,特别是对于移动用户或从远程位置访问的应用程序的用户而言。
1.3 应用场景
响应结果很大
如果你的API返回大的JSON或XML响应,压缩数据可以显著减少响应时间。
静态内容
压缩HTML、CSS和JavaScript文件等静态资源可以改善页面加载时间
注意:如果对应响应结果比较小的(小于2kb)时候反而使用压缩技术会对性能造成影响。
2. 实战案例
2.1 Deflate过滤器
public class DeflateCompressionFilter implements Filter {private static final int MIN_RESPONSE_SIZE = 2 * 1024 ;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");// 这里我们更加请求header中的Accept-Encoding进行判断,只有包含指定的值才进行处理if (acceptEncoding == null || !acceptEncoding.toLowerCase().contains("deflate")) {chain.doFilter(request, response);return;}// 自定义Response包装类,我们需要对响应结果进行获取处理DeflateResponseWrapper responseWrapper = new DeflateResponseWrapper(resp);chain.doFilter(request, responseWrapper);// 只有响应的数据大小超过这里指定的值(2KB)才进行压缩处理if (responseWrapper.getContentLength() > MIN_RESPONSE_SIZE) {// 必须设置,否则客户端将无法解析解压数据resp.setHeader("Content-Encoding", "deflate");try (DeflaterOutputStream dos= new DeflaterOutputStream(resp.getOutputStream())) {dos.write(responseWrapper.getCapturedData());}} else {// Write the uncompressed responseresp.getOutputStream().write(responseWrapper.getCapturedData());}}}
关键的注释已经在源码中进行了处理。
注意:这里没有判断响应数据的类型可以根据Content-Type进行判断。
2.2 Response包装类
public class DeflateResponseWrapper extends HttpServletResponseWrapper {private final ByteArrayOutputStream capture;private ServletOutputStream outputStream;private PrintWriter writer;public DeflateResponseWrapper(HttpServletResponse response) {super(response);capture = new ByteArrayOutputStream() ;}public ServletOutputStream getOutputStream() {if (writer != null) {throw new IllegalStateException("Writer already in use");}if (outputStream == null) {outputStream = new ServletOutputStream() {public void write(int b) throws IOException {capture.write(b);}public void flush() throws IOException {capture.flush();}public void close() throws IOException {capture.close();}public boolean isReady() {return true;}public void setWriteListener(WriteListener writeListener) {}};}return outputStream;}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 注册过滤器
在Spring Boot中我们可以通过如下方式注册过滤器,也可以通过@WedFilter的方式注册。
FilterRegistrationBean<DeflateCompressionFilter> deflateCompressionFilter() {FilterRegistrationBean<DeflateCompressionFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new DeflateCompressionFilter());// 对所有的请求都进行过去了处理registrationBean.addUrlPatterns("/*") ;registrationBean.setName("DeflateCompressionFilter") ;registrationBean.setOrder(1) ;return registrationBean ;}
以上我们就完成了所有的代码,接下来我们进行测试。
2.4 测试
接下来,我们通过如下接口进行测试:
@GetMapping("/data")public List<User> getData() {List<User> data = new ArrayList<>() ;for (long i = 0; i < 10000; i++) {data.add(new User(i, "姓名 - " + i, new Random().nextInt(100))) ;}return data;}public static record User (Long id, String name, Integer age) {}
首先,我们将请求的Accept-Encoding随意写一个值,响应结果
最后,我们在将Accept-Encoding设置为deflate,响应结果:
与压缩前相比:压缩了近6.7倍。
显著提升应用程序的性能,减少带宽使用,并增强用户体验。
注意:你完全可以使用GZIP进行压缩,并且使用GZIP也是当前最为推荐流行的方式,并且兼容性要比deflate好。
如果启用GZIP?如下配置即可:
server:compression:enabled: truemin-response-size: 1024mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml
而本篇文章的目标是让你了解这压缩技术的实现原理。而在上面自定义的过滤器中,我们也完全可以使用GZIP对应的输出流进行压缩数据,如下代码:
if (responseWrapper.getContentLength() > MIN_RESPONSE_SIZE) {// 设置响应的内容编码类型为gzipresp.setHeader("Content-Encoding", "gzip");// 使用gzip进行压缩数据try (GZIPOutputStream gos = new GZIPOutputStream(resp.getOutputStream())) {gos.write(responseWrapper.getCapturedData()) ;}} else {resp.getOutputStream().write(responseWrapper.getCapturedData());}
以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
推荐文章
查漏补缺!OpenFeign整合Resilience4j,你真的会用吗?
高级开发!性能优化,Spring Boot 不使用AOP也能优雅的记录日志
优雅!Spring Boot 一个注解轻松实现敏感词检查,支持多场景
SpringBoot自带Controller接口监控,赶紧用起来
Tika 与 Spring Boot 的完美结合:支持任意文档解析的神器
我给Spring提交一个Bug,已在最新版修复!请这样修复!



