当前位置: 首页 > 工具软件 > Kryo > 使用案例 >

Kryo配合Redis使用(在SpringBoot项目中)

韦原
2023-12-01

Kryo配合Redis使用(在SpringBoot项目中)

todo今日将Kryo融入项目中,替换掉原本的序列化工具!

Kryo是什么?Kryo时是一种快速高效的Java序列化框架 该项目的目标是速度、效率和易于使用的API。 当对象需要持久化时,无论是用于文件、数据库还是通过网络,该项目都很有用。

在SpringBoot中使用,为了提高Redis写入和节约储存,使用Kryo来代替原本的序列化工具

  • 先导入kryo的Maven。
        <!-- https://mvnrepository.com/artifact/com.esotericsoftware/kryo -->
        <dependency>
            <groupId>com.esotericsoftware</groupId>
            <artifactId>kryo</artifactId>
            <version>5.3.0</version>
        </dependency>

使用前提需要导入Redis对应的项目包

  • 编写 KryoRedisSerializerConfig (名称自取)
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);
	}
  }
}

  • 编写 RedisTemplateConfig 类(Redis序列化的配置类)

/***
 * 自动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;
  }

}
  • 在RedisUtils替代掉原本的Redis序列化工具(这个自己编写Redis工具类)
@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);
  }
 }

结果没有问题

 类似资料: