spring-data-redis使用自定义序列化数据 使用 protobuf
来源:互联网 发布:可以ps图片的软件 编辑:程序博客网 时间:2024/05/18 03:16
spring-data-redis提供了多种serializer策略,这对使用jedis的开发者而言,实在是非常便捷。sdr提供了4种内置的serializer:
- JdkSerializationRedisSerializer:使用JDK的序列化手段(serializable接口,ObjectInputStrean,ObjectOutputStream),数据以字节流存储,jdk序列化和反序列化数据
- StringRedisSerializer:字符串编码,数据以string存储
- JacksonJsonRedisSerializer:json格式存储
- OxmSerializer:xml格式存储
其中JdkSerializationRedisSerializer和StringRedisSerializer是最基础的序列化策略,其中“JacksonJsonRedisSerializer”与“OxmSerializer”都是基于stirng存储,因此它们是较为“高级”的序列化(最终还是使用string解析以及构建java对象)。
RedisTemplate中需要声明4种serializer,默认为“JdkSerializationRedisSerializer”:
1) keySerializer :对于普通K-V操作时,key采取的序列化策略
2) valueSerializer:value采取的序列化策略
3) hashKeySerializer: 在hash数据结构中,hash-key的序列化策略
4) hashValueSerializer:hash-value的序列化策略
无论如何,建议key/hashKey采用StringRedisSerializer。 这redis服务端用命令行好查看 配置如下:
< ! -- redis template definition -- > < bean id = "redisTemplate" class = "org.springframework.data.redis.core.RedisTemplate" p : connection - factory - ref = "jedisConnFactory" scope = "prototype" > < ! -- 使用string主要是key 在 redis 端用命令好读 不然默认的序列化没办法读 -- > < property name = "keySerializer" > < bean class = "org.springframework.data.redis.serializer.StringRedisSerializer" / > < / property > < property name = "hashKeySerializer" > < bean class = "org.springframework.data.redis.serializer.StringRedisSerializer" / > < / property > < / bean >
二、 自定义序列化处理效果
默认是JdkSerializationRedisSerializer存储,占用空间比较大,如图:
类字段信息,字段信息都在里面,如果对于大数据量存储,内存成本很高。 其他的序列化存储也是类似,只是稍微少点。这里使用google protobuf改造序列化。改造后存储如下:
可以发现存储数据减少一半以上。
三、 自定义序列化处理过程
package org.springframework.data.redis.serializer; import java.lang.reflect.Method; import com.google.protobuf.GeneratedMessage; /*** @date 2013年12月27日 上午11:18:23 * @version V1.0 * @param <T>* @Description: protocbuf 序列化数据 减少存储空间* 存在问题,必须设置对应type,这样的话RedisTemplate单例就没有办法是用了!,是用多例 * <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnFactory" scope="prototype">*/public class ProtocbufRedisSerializer < T > implements RedisSerializer < T > { private Class < T > type; public ProtocbufRedisSerializer(Class < T > type){ this .type = type; } @Override public byte [] serialize(Object t) throws SerializationException { if (t == null) { return SerializationUtils.EMPTY_ARRAY; } try { GeneratedMessage gm = (GeneratedMessage)t; return gm.toByteArray(); } catch (Exception ex) { throw new SerializationException( "Cannot serialize" , ex); } } @SuppressWarnings( "unchecked" ) @Override public T deserialize( byte [] bytes) throws SerializationException { if (SerializationUtils.isEmpty(bytes)) { return null; } try { Method method = type.getMethod( "parseFrom" , new Class[]{bytes.getClass()}); return (T)method.invoke(type, new Object[]{bytes}); } catch (Exception ex) { throw new SerializationException( "Cannot deserialize" , ex); } } public Class < T > getType() { return type; } public void setType(Class < T > type) { this .type = type; }}
应为在deserialize时候需要对应类的类型,所以这里反序列化需要使用对应的解析类来处理。这样导致一个问题,我们没有办法使用单例去配置,因为每个解析类都不一样。所以在配置的时候需要使用多例。scope="prototype",在应用中代码如下:package com.vrv.im.service.impl.helper; import java.util.ArrayList;import java.util.List; import javax.annotation.Resource; import org.springframework.beans.BeanUtils;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.ProtocbufRedisSerializer;import org.springframework.stereotype.Component; import com.vrv.im.domain.IMCommentSubject;import com.vrv.im.protoc.Comment.CommentSubjectInfo; /*** @date 2013年12月26日 上午11:47:22 * @version V1.0 * @param <K>* @param <V>* @Description: 缓存新鲜事的最近两条评论,所有的新鲜事,* protocbuf序列化压缩数据* 存在问题,必须设置对应type,这样的话RedisTemplate单例就没有办法是用了!,是用多例 * <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnFactory" scope="prototype">*/@Componentpublic class CommentInfoCacheHandlerForProtocbuf<K, V> { @Resource private RedisTemplate<String, CommentSubjectInfo> template; private String commentInfoKey="commentInfo"; /** * 获取缓存评论 * @param subjectCommentID * @return */ @SuppressWarnings({ "unchecked", "rawtypes" }) public List<IMCommentSubject> getCommentInfoCache(long subjectCommentID){ List<IMCommentSubject> commentList = new ArrayList<IMCommentSubject>(); template.setValueSerializer(new ProtocbufRedisSerializer(CommentSubjectInfo.class)); List<CommentSubjectInfo> list= template.opsForList().range(commentInfoKey+"_"+subjectCommentID, 0, -1);//获取所有 if(list==null) list= new ArrayList<CommentSubjectInfo>(); for(CommentSubjectInfo info :list){ IMCommentSubject subject = new IMCommentSubject(); BeanUtils.copyProperties(info, subject); commentList.add(subject); } return commentList; } /** * 添加缓存信息 * @param commentInfo */ public void addCommentInfoCache(IMCommentSubject commentInfo){ template.setValueSerializer(new ProtocbufRedisSerializer(CommentSubjectInfo.class)); CommentSubjectInfo inf= CommentSubjectInfo.newBuilder() .setSubjectCommentID(commentInfo.getSubjectCommentID()) .setCommentID(commentInfo.getCommentID()) .setCommentUser(commentInfo.getCommentUser()) .setCreateTime(commentInfo.getCreateTime()) .setComment(commentInfo.getComment()) .setReplyToUser(commentInfo.getReplyToUser()) .build(); template.opsForList().leftPush(commentInfoKey+"_"+commentInfo.getSubjectCommentID(), inf); template.opsForList().trim(commentInfoKey+"_"+commentInfo.getSubjectCommentID(), 0, 1);//保留2条 } /** * 删除评论主体缓存 * @param subjectCommentID */ public void deleteCommentInfoCache(long subjectCommentID){ template.delete(commentInfoKey+"_"+subjectCommentID);//所有都删除 } /** * 删除评论主体的某条评论 * @param subjectCommentID */ public void deleteCommentInfoCache(IMCommentSubject commentInfo){ template.setValueSerializer(new ProtocbufRedisSerializer(CommentSubjectInfo.class)); CommentSubjectInfo inf= CommentSubjectInfo.newBuilder() .setSubjectCommentID(commentInfo.getSubjectCommentID()) .setCommentID(commentInfo.getCommentID()) .setCommentUser(commentInfo.getCommentUser()) .setCreateTime(commentInfo.getCreateTime()) .setComment(commentInfo.getComment()) .setReplyToUser(commentInfo.getReplyToUser()) .build(); template.opsForList().remove(commentInfoKey+"_"+commentInfo.getSubjectCommentID(), 0, inf);//相等的评论信息 }}
附proto文件
package com.vrv.im.protoc;//评论信息类message CommentSubjectInfo{ required sint64 subjectCommentID = 1; required sint64 commentUser = 2; required sint64 replyToUser = 3; required string comment = 4; required sint64 commentID = 5; required sint64 createTime = 6; }
private ValueOperations<K, V> valueOps ; private ListOperations<K, V> listOps ; private SetOperations <K, V> setOps ; private ZSetOperations<K, V> zSetOps ;
这样在使用上面的方式的时候,如果遇到hash类型,就没有办法设置setValueSerializer,尝试过用
@Resource (name= "redisTemplate" ) private HashOperations<String,String,Long> subjectCommentNumHash
- spring-data-redis使用自定义序列化数据 使用 protobuf
- spring-data-redis 使用 protobuf进行序列化和反序列
- Redis 使用spring-data-redis的序列化问题
- 使用kryo作为spring data redis的序列化器
- spring-data-redis 使用
- spring-data-redis 使用
- Spring Data Redis 使用
- spring data redis使用
- spring-data-redis 整合,以及使用kryo序列化代替jdk原生序列化机制
- Simple-Spring-Memcached使用Protobuf序列化Java对象
- spring-data-redis 使用过程中需要注意的一点(序列化选择)
- spring-data-redis使用jdk序列化时increment的异常
- Spring+redis,spring-data-redis使用
- Spring Data Redis快速使用
- Spring-Data-Redis使用文档
- spring-data集成redis使用 数据集合池
- 使用spring-data-redis操作redis
- 使用spring-data-redis开发redis应用
- 移动端与服务器端数据库同步
- 【转】Linux进程状态浅析
- 项目总结—jQuery EasyUI-Tree使用
- Java中的lock和synchronized区别是什么
- 無極體位度數
- spring-data-redis使用自定义序列化数据 使用 protobuf
- WebLoigic文件被锁解决方案
- CAS实现SSO单点登录原理
- 微信公众号快速增粉攻略详解
- Qt应用程序换肤操作(拖动图片)
- 【转】Wince Device Emulator使用介绍-Device Emulator 2.0
- vmware的vcenter不能打开虚拟机控制台
- How to Stop a Thread or a Task(http://forward.com.au/javaProgramming/HowToStopAThread.html)
- Android平台上的JNI技术介绍