1.为什么需要压缩json?
由于业务需要,存入redis中的缓存数据过大,占用了10+g的内存,内存作为重要资源,需要优化一下大对象缓存,采用gzip压缩存储,可以将 redis 的 kv 对大小缩小大约 7-8 倍,加快存储、读取速度
2.环境搭建
详建redis模块的docker目录
version: '3' services: redis: image: registry.cn-hangzhou.aliyuncs.com/zhengqing/redis:6.0.8 container_name: redis restart: unless-stopped command: redis-server /etc/redis/redis.conf --requirepass 123456 --appendonly no # command: redis-server --requirepass 123456 --appendonly yes environment: tz: asia/shanghai lang: en_us.utf-8 volumes: - "./redis/data:/data" - "./redis/config/redis.conf:/etc/redis/redis.conf" ports: - "6379:6379"
3.代码工程
实验目标
实验存入redis的json数据压缩和解压缩
pom.xml
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactid>springboot-demo</artifactid> <groupid>com.et</groupid> <version>1.0-snapshot</version> </parent> <modelversion>4.0.0</modelversion> <artifactid>gzip</artifactid> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-autoconfigure</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-redis</artifactid> </dependency> <dependency> <groupid>org.apache.commons</groupid> <artifactid>commons-pool2</artifactid> <version>2.9.0</version> </dependency> </dependencies> </project>
controller
package com.et.gzip.controller; import com.et.gzip.model.user; import lombok.extern.slf4j.slf4j; import org.springframework.beans.factory.annotation.autowired; import org.springframework.data.redis.core.redistemplate; import org.springframework.web.bind.annotation.postmapping; import org.springframework.web.bind.annotation.requestbody; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.restcontroller; import java.util.hashmap; import java.util.map; @restcontroller @slf4j public class helloworldcontroller { @autowired private redistemplate redistemplatewithjackson; @postmapping("/hello") public user showhelloworld(@requestbody user user){ log.info("user:"+ user); return user; } @postmapping("/redis") public user redis(@requestbody user user){ log.info("user:"+ user); redistemplatewithjackson.opsforvalue().set("user",user); user redisuser = (user) redistemplatewithjackson.opsforvalue().get("user"); return redisuser; } }
redis压缩和解压缩配置
压缩类
package com.et.gzip.config; import com.et.gzip.model.user; import com.fasterxml.jackson.databind.objectmapper; import com.fasterxml.jackson.databind.annotation.jsonserialize; import lombok.extern.slf4j.slf4j; import org.apache.tomcat.util.http.fileupload.ioutils; import org.springframework.data.redis.serializer.jdkserializationredisserializer; import org.springframework.data.redis.serializer.serializationexception; import sun.misc.base64encoder; import java.io.bytearrayinputstream; import java.io.bytearrayoutputstream; import java.text.simpledateformat; import java.util.zip.gzipinputstream; import java.util.zip.gzipoutputstream; @slf4j public class compressredis extends jdkserializationredisserializer { public static final int buffer_size = 4096; private jacksonredisserializer<user> jacksonredisserializer; public compressredis() { this.jacksonredisserializer = getvalueserializer(); } @override public byte[] serialize(object graph) throws serializationexception { if (graph == null) { return new byte[0]; } bytearrayoutputstream bos = null; gzipoutputstream gzip = null; try { // serialize byte[] bytes = jacksonredisserializer.serialize(graph); log.info("bytes size{}",bytes.length); bos = new bytearrayoutputstream(); gzip = new gzipoutputstream(bos); // compress gzip.write(bytes); gzip.finish(); byte[] result = bos.tobytearray(); log.info("result size{}",result.length); //return result; return new base64encoder().encode(result).getbytes(); } catch (exception e) { throw new serializationexception("gzip serialization error", e); } finally { ioutils.closequietly(bos); ioutils.closequietly(gzip); } } @override public object deserialize(byte[] bytes) throws serializationexception { if (bytes == null || bytes.length == 0) { return null; } bytearrayoutputstream bos = null; bytearrayinputstream bis = null; gzipinputstream gzip = null; try { bos = new bytearrayoutputstream(); byte[] compressed = new sun.misc.base64decoder().decodebuffer( new string(bytes));; bis = new bytearrayinputstream(compressed); gzip = new gzipinputstream(bis); byte[] buff = new byte[buffer_size]; int n; // uncompress while ((n = gzip.read(buff, 0, buffer_size)) > 0) { bos.write(buff, 0, n); } //deserialize object result = jacksonredisserializer.deserialize(bos.tobytearray()); return result; } catch (exception e) { throw new serializationexception("gzip deserizelie error", e); } finally { ioutils.closequietly(bos); ioutils.closequietly(bis); ioutils.closequietly(gzip); } } private static jacksonredisserializer<user> getvalueserializer() { jacksonredisserializer<user> jackson2jsonredisserializer = new jacksonredisserializer<>(user.class); objectmapper mapper=new objectmapper(); jackson2jsonredisserializer.setobjectmapper(mapper); return jackson2jsonredisserializer; } }
java序列化
package com.et.gzip.config; import com.fasterxml.jackson.databind.javatype; import com.fasterxml.jackson.databind.objectmapper; import com.fasterxml.jackson.databind.type.typefactory; import lombok.extern.slf4j.slf4j; import org.springframework.data.redis.serializer.redisserializer; import org.springframework.data.redis.serializer.serializationexception; import org.springframework.lang.nullable; import org.springframework.util.assert; import java.nio.charset.charset; import java.nio.charset.standardcharsets; @slf4j public class jacksonredisserializer<t> implements redisserializer<t> { public static final charset default_charset; private final javatype javatype; private objectmapper objectmapper = new objectmapper(); public jacksonredisserializer(class<t> type) { this.javatype = this.getjavatype(type); } public jacksonredisserializer(javatype javatype) { this.javatype = javatype; } public t deserialize(@nullable byte[] bytes) throws serializationexception { if (bytes == null || bytes.length == 0) { return null; } else { try { return this.objectmapper.readvalue(bytes, 0, bytes.length, this.javatype); } catch (exception var3) { throw new serializationexception("could not read json: " + var3.getmessage(), var3); } } } public byte[] serialize(@nullable object t) throws serializationexception { if (t == null) { return new byte[0]; } else { try { return this.objectmapper.writevalueasbytes(t); } catch (exception var3) { throw new serializationexception("could not write json: " + var3.getmessage(), var3); } } } public void setobjectmapper(objectmapper objectmapper) { assert.notnull(objectmapper, "'objectmapper' must not be null"); this.objectmapper = objectmapper; } protected javatype getjavatype(class<?> clazz) { return typefactory.defaultinstance().constructtype(clazz); } static { default_charset = standardcharsets.utf_8; } }
redis序列化
package com.et.gzip.config; import com.et.gzip.model.user; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.data.redis.connection.lettuce.lettuceconnectionfactory; import org.springframework.data.redis.core.redistemplate; import org.springframework.data.redis.serializer.redisserializer; import org.springframework.data.redis.serializer.stringredisserializer; @configuration public class rediswithjacksonconfig { @bean(name="redistemplatewithjackson") public redistemplate<string, user> redistemplate(lettuceconnectionfactory lettuceconnectionfactory) { compressredis compressredis = new compressredis(); //redistemplate redistemplate<string, user> redistemplate = new redistemplate<>(); redistemplate.setconnectionfactory(lettuceconnectionfactory); redisserializer<?> stringserializer = new stringredisserializer(); redistemplate.setkeyserializer(stringserializer); redistemplate.setvalueserializer(compressredis); redistemplate.sethashkeyserializer(stringserializer); redistemplate.sethashvalueserializer(compressredis); redistemplate.afterpropertiesset(); return redistemplate; } }
application.yaml
spring: redis: host: 127.0.0.1 port: 6379 database: 10 password: 123456 timeout: 10s lettuce: pool: min-idle: 0 max-idle: 8 max-active: 8 max-wait: -1ms server: port: 8088 compression: enabled: true mime-types: application/json,application/xml,text/html,text/plain,text/css,application/x-javascript
以上只是一些关键代码,所有代码请参见下面代码仓库
代码仓库
4.测试
- 启动spring boot应用
- 用postman访问http://127.0.0.1:8088/redis
可以看到redis里面存储的是gzip压缩的内容
查看控制台日志
2024-08-26 14:37:56.445 info 43832 --- [nio-8088-exec-5] com.et.gzip.config.compressredis : bytes size371 2024-08-26 14:37:56.445 info 43832 --- [nio-8088-exec-5] com.et.gzip.config.compressredis : result size58
json经过gzip压缩,371-->58, 数据大小减少7-8倍
到此这篇关于springboot压缩json并写入redis的示例代码的文章就介绍到这了,更多相关springboot压缩json内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论