todo今日将Kryo融入项目中,替换掉原本的序列化工具!
Kryo是什么?Kryo时是一种快速高效的Java序列化框架 该项目的目标是速度、效率和易于使用的API。 当对象需要持久化时,无论是用于文件、数据库还是通过网络,该项目都很有用。
在SpringBoot中使用,为了提高Redis写入和节约储存,使用Kryo来代替原本的序列化工具
<!-- https://mvnrepository.com/artifact/com.esotericsoftware/kryo -->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.3.0</version>
</dependency>
使用前提需要导入Redis对应的项目包
package com.dushuren.project.config;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import lombok.NoArgsConstructor;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@Component
@NoArgsConstructor
public class KryoRedisSerializerConfig<T> implements RedisSerializer<T> {
/**
* 由于 Kryo 不是线程安全的。每个线程都应该有自己的 Kryo,Input 或 Output 实例。
* 所以,使用 ThreadLocal 存放 Kryo 对象
* 这样减少了每次使用都实例化一次 Kryo 的开销又可以保证其线程安全
*/
private static final ThreadLocal<Kryo> KRYO_THREAD_LOCAL = ThreadLocal.withInitial(() -> {
Kryo kryo = new Kryo();
// 设置循环引用
kryo.setReferences(true);
// 设置序列化时对象是否需要设置对象类型
kryo.setRegistrationRequired(false);
return kryo;
});
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
@Override
public byte[] serialize(Object t) throws SerializationException {
if (t == null) {
return EMPTY_BYTE_ARRAY;
}
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
Output output = new Output(baos)) {
Kryo kryo = KRYO_THREAD_LOCAL.get();
// 对象的 Class 信息一起序列化
kryo.writeClassAndObject(output, t);
KRYO_THREAD_LOCAL.remove();
return output.toBytes();
} catch (Exception e) {
throw new SerializationException("Could not write byte[]: " + e.getMessage(), e);
}
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
Input input = new Input(bais)) {
Kryo kryo = KRYO_THREAD_LOCAL.get();
// 通过存储在字节数组中的 Class 信息来确定反序列的类型
Object object = kryo.readClassAndObject(input);
KRYO_THREAD_LOCAL.remove();
return (T) object;
} catch (IOException e) {
throw new SerializationException("Could not read byte[]: " + e.getMessage(), e);
}
}
}
/***
* 自动redis序列器
*/
@Configuration
public class RedisTemplateConfig {
// 这个对应的就是原生的序列化
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
//必须执行这个函数,初始化RedisTemplate
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
// 这个和下面起到一个映射的效果
@Bean("kryoRedisTemplate")
public RedisTemplate<String, Object> kryoRedisTemplate(LettuceConnectionFactory connectionFactory) {
// key序列化
RedisSerializer<?> keySerializer = new StringRedisSerializer();
// value序列化
KryoRedisSerializerConfig<Object> valueSerializer = new KryoRedisSerializerConfig<>();
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
// key序列化
redisTemplate.setKeySerializer(keySerializer);
// value序列化
redisTemplate.setValueSerializer(valueSerializer);
// Hash key序列化
redisTemplate.setHashKeySerializer(keySerializer);
// Hash value序列化
redisTemplate.setHashValueSerializer(valueSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
@Component
public class RedisUtils {
// 这个是自带的
// @Resource
// private RedisTemplate<String, Object> redisTemplate;
// 这里进行一个映射
@Resource(name = "kryoRedisTemplate")
private RedisTemplate<String, Object> kryoRedisTemplate;
/***
* 写入 缓存
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations operations = kryoRedisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
throw new BusinessException(ErrorCode.STORAGE_ERROR);
}
return result;
}
}
@SpringBootTest
public class TestCS {
@Resource(name = "kryoRedisTemplate")
private RedisTemplate<String, Object> kryoRedisTemplate;
@Test
void testKryo() {
Gson gson = new Gson();
User user = new User();
user.setId(1L);
user.setUserAccount("asdasd");
user.setUserPassword("sdasd");
user.setUserName("asdasd");
String key = "USER";
redisUtils.set(key, gson.toJson(user), 300000L);
String userOb = (String) redisUtils.get("Usera");
System.out.println("1:" + userOb);
}
}
结果没有问题