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内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论