前言

由于Springboot默认提供了序列化方式并不是非常理想,对于高要求的情况下,序列化的速度和序列化之后大小有要求的情况下,不能满足,所以可能需要更换序列化的方式。
这里主要记录更换序列化的方式以及其中一些出现问题。
坑坑坑坑坑坑!!!
这次踩的坑坑。

序列化方式更换

第一步,加入依赖

//protostuff序列化依赖
compile group: 'io.protostuff', name: 'protostuff-runtime', version: '1.6.0'
compile group: 'io.protostuff', name: 'protostuff-core', version: '1.6.0'

第二步,加入序列化工具

import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException; /**
* ProtoStuff序列化工具
* @author LinkinStar
*/
public class ProtostuffSerializer implements RedisSerializer { private boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
} private final Schema<ProtoWrapper> schema; private final ProtoWrapper wrapper; private final LinkedBuffer buffer; public ProtostuffSerializer() {
this.wrapper = new ProtoWrapper();
this.schema = RuntimeSchema.getSchema(ProtoWrapper.class);
this.buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
} @Override
public byte[] serialize(Object t) throws SerializationException {
if (t == null) {
return new byte[0];
}
wrapper.data = t;
try {
return ProtostuffIOUtil.toByteArray(wrapper, schema, buffer);
} finally {
buffer.clear();
}
} @Override
public T deserialize(byte[] bytes) throws SerializationException {
if (isEmpty(bytes)) {
return null;
}
ProtoWrapper newMessage = schema.newMessage();
ProtostuffIOUtil.mergeFrom(bytes, newMessage, schema);
return (T) newMessage.data;
} private static class ProtoWrapper {
private Object data;
}
}

第三步,对RedisTemplate进行封装

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; /**
* Redis操作工具类
* @author LinkinStar
*/
@Component
public class RedisUtil { @Autowired
@Qualifier("protoStuffTemplate")
private RedisTemplate protoStuffTemplate; /**
* 设置过期时间,单位秒
* @param key 键的名称
* @param timeout 过期时间
* @return 成功:true,失败:false
*/
public boolean setExpireTime(String key, long timeout) {
return protoStuffTemplate.expire(key, timeout, TimeUnit.SECONDS);
} /**
* 通过键删除一个值
* @param key 键的名称
*/
public void delete(String key) {
protoStuffTemplate.delete(key);
} /**
* 判断key是否存在
* @param key 键的名称
* @return 存在:true,不存在:false
*/
public boolean hasKey(String key) {
return protoStuffTemplate.hasKey(key);
} /**
* 数据存储
* @param key 键
* @param value 值
*/
public void set(String key, Object value) {
protoStuffTemplate.boundValueOps(key).set(value);
} /**
* 数据存储的同时设置过期时间
* @param key 键
* @param value 值
* @param expireTime 过期时间
*/
public void set(String key, Object value, Long expireTime) {
protoStuffTemplate.boundValueOps(key).set(value, expireTime, TimeUnit.SECONDS);
} /**
* 数据取值
* @param key 键
* @return 查询成功:值,查询失败,null
*/
public Object get(String key) {
return protoStuffTemplate.boundValueOps(key).get();
}
}

第四步,修改默认序列化方式

import com.linkinstars.springBootTemplate.util.ProtostuffSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; /**
* redisTemplate初始化,开启spring-session redis存储支持
* @author LinkinStar
*/
@Configuration
@EnableRedisHttpSession
public class RedisConfig { /**
* redisTemplate 序列化使用的Serializeable, 存储二进制字节码, 所以自定义序列化类
* @Rparam redisConnectionFactory
* @return redisTemplate
*/
@Bean
public RedisTemplate<Object, Object> protoStuffTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory); // redis value使用的序列化器
template.setValueSerializer(new ProtostuffSerializer());
// redis key使用的序列化器
template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet();
return template;
}
}

第五步,相应测试

//测试redis
UserEntity user = new UserEntity();
user.setId(1);
user.setVal("xxx"); redisUtil.set("xxx", user);
Object object = redisUtil.get("xxx");
UserEntity userTemp = (UserEntity) object; System.out.println("redis数据获取为: " + userTemp);
redisUtil.delete("xxx");
System.out.println("redis删除数据之后获取为: " + redisUtil.get("xxx"));

遇到问题

问题描述:序列化之后反序列化没有问题,但是强制转换成对应的类出现问题,抛出无法强制转换的异常。
问题分析:无法强制转换说明可能两个类的类加载器不一样,所以打印两者类加载器发现确实不一样。
发现其中一个类的类加载器出现了devtool的字样
所以联想到可能是热部署机制导致这样问题的产生。
然后查询网络资料,并在多台机器上进行测试,发现有的机器不会出现这样的问题,而有的机器就会出现。
如果使用Kryo进行序列化的话,第一次就会出现上述问题,而使用protostuff热部署之后才会出现上述问题。
问题解决:最后为了免除后续可能出现的问题,注释了热部署的devtool的相应依赖和相应的配置得以解决。

完整代码

github:https://github.com/LinkinStars/springBootTemplate

参考博客:
https://www.spldeolin.com/posts/redis-template-protostuff/
https://blog.csdn.net/wsywb111/article/details/79612081
https://github.com/protostuff/protostuff

SpringBoot修改Redis序列化方式的更多相关文章

  1. SpringBoot2.x修改Redis序列化方式

    添加一个配置类即可: /** * @Author FengZeng * @Date 2022-03-22 13:43 * @Description TODO */ @Configuration pub ...

  2. Redis 序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer

    当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的.RedisTemplate默认使用的是JdkSerializat ...

  3. SpringBoot中redis的使用介绍

    REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统. Redis是一个开源的使用ANSI C语言编写.遵守B ...

  4. springBoot集成Redis,RedisTmple操作redis和注解实现添加和清空缓存功能

    配置 maven项目进入相关配置 <dependency>    <groupId>org.springframework.boot</groupId>    &l ...

  5. SpringBoot项目使用RedisTemplate设置序列化方式

    前端时间新项目使用SpringBoot的RedisTemplate遇到一个问题,先简单描述一下问题:不同项目之间redis共用一个,但是我们新项目读不到老项目存储的缓存.新项目搭建的时候没有跟老项目使 ...

  6. 【springBoot】springBoot集成redis的key,value序列化的相关问题

    使用的是maven工程 springBoot集成redis默认使用的是注解,在官方文档中只需要2步; 1.在pom文件中引入即可 <dependency> <groupId>o ...

  7. SpringBoot集成redis的key,value序列化的相关问题

    使用的是maven工程 springBoot集成redis默认使用的是注解,在官方文档中只需要2步; 1.在pom文件中引入即可 <dependency> <groupId>o ...

  8. Springboot+Redis序列化坑

    今天在测试springboot整合redis的时候遇到下面这个坑,百度来百度去发现提示都是ajax的问题,真的是醉了,错误提示如下所示,不信大家可以直接复制百度一下答案是什么(流泪中....),错误如 ...

  9. 三种序列化方式存取redis的方法

    常见的的序列化反序列方式的效率: protoBuf(PB) > fastjson > jackson > hessian > xstream > java 数据来自于:h ...

随机推荐

  1. vue-nuxtjs

    1.创建项目:npm create-nuxt-app projectName 2.npm i sass-loader node-sass

  2. 利用Github免费搭建个人主页(转)

    搭建过程涉及: Github注册 Github搭建博客 域名选购 绑定域名 更多 一.  Github注册 在地址栏输入地址:http://github.com/join填写相关信息, 按步骤完成即可 ...

  3. Java 跨平台原理

    Java的跨平台基于编译器和虚拟机.其中,CPU处理器和操作系统的整体称为平台.编译器把源文件编译成与平台无关的基于Unicode的字节码class文件,虚拟机把该文件解释成与平台有关的机器码指令,可 ...

  4. 神奇高效的Linux命令行

    一.为什么要学linux命令 Linux是由命令行组成的操作系统,精髓在命令行,无论图形界面发展到什么水平,命令行方式的操作永远是不会变的.Linux命令有许多强大的功能:从简单的磁盘操作.文件存取, ...

  5. Visual Studio2012 添加服务引用时,生成基于任务操作不可用原因

    今天在添加服务引用时,发现 单选按钮 ”生成基于任务操作“不可用,原因项目选择的.net frame是3.5,调整为.net 4.5或.net4.6即可. 原因:.net4.5以下的环境不支持.

  6. 2.postman安装及使用

    一.postman说明 postman是研发和测试进行接口调试的工具.可以用来很方便的模拟get或者post或者其他方式的请求来调试接口. 二.postman安装 ①作为谷歌浏览器插件安装 参考资料: ...

  7. webpack-dev-server和webpack-dev-middleware的区别

    webpack-dev-server webpack-dev-server实际上相当于启用了一个express的Http服务器+调用webpack-dev-middleware.它的作用主要是用来伺服 ...

  8. 控件包含代码块(即 <% ... %>),因此无法修改控件集合。

    原因分析:在head里写的js代码中包含了<%=...%>代码 解决:把js的代码放到body中...

  9. 网页开发--03(wampserver安装服务无法启动的问题)

    一.安装wampserver 一路next,指定安装路径外,其它默认安装. 二.我遇到的问题 当任务图标绿色为正常启动状态,但是我的从打开一直是黄色,问题在于Apache和MySql 1)Apache ...

  10. 又到毕业季,尚学堂喊你免费领取100个Java毕设项目(含源码视频),限时一周哦!

    你还在为毕设发愁?不知道该如何命题?不知道从哪里下手?担心毕设过不了影响毕业? 尚学堂首家隆重推出了刷爆朋友圈的毕设100个项目,别说你还没去下载观看!!最最重要的是:免费!免费!免费!而且限时一周! ...