热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

spring-data-redis使用自定义序列化数据使用protobuf

一、spring-data-redis序列化策略spring-data-redis提供了多种serializer策略,这对使用jedis的开发者而言,实在是非常便捷。sdr提供了4
一、 spring-data-redis序列化策略

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服务端用命令行好查看 配置如下:


class = "org.springframework.data.redis.core.RedisTemplate"
p : connection - factory - ref = "jedisConnFactory" scope = "prototype" >









二、 自定义序列化处理效果

默认是JdkSerializationRedisSerializer存储,占用空间比较大,如图:


类字段信息,字段信息都在里面,如果对于大数据量存储,内存成本很高。 其他的序列化存储也是类似,只是稍微少点。这里使用google protobuf改造序列化。改造后存储如下:


可以发现存储数据减少一半以上。


三、 自定义序列化处理过程

 1、添加自定义序列化处理类
主要是实现RedisSerializer接口,使用protocbuf,就需要使用它的序列化方式,serialize对应protocbuf生成类的toByteArray方法,deserialize对应protocbuf生成类的parseFrom方法,代码如下:
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
* @Description: protocbuf 序列化数据 减少存储空间
* 存在问题,必须设置对应type,这样的话RedisTemplate单例就没有办法是用了!,是用多例
* class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnFactory" scope="prototype">
*/
public class ProtocbufRedisSerializer implements RedisSerializer {

private Class type;

public ProtocbufRedisSerializer(Class 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 getType() {
return type;
}
public void setType(Class type) {
this .type = type;
}
}

2、使用protobuf序列化处理
应为在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
* @param
* @Description: 缓存新鲜事的最近两条评论,所有的新鲜事,
* protocbuf序列化压缩数据
* 存在问题,必须设置对应type,这样的话RedisTemplate单例就没有办法是用了!,是用多例
* class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnFactory" scope="prototype">
*/
@Component
public class CommentInfoCacheHandlerForProtocbuf {
@Resource
private RedisTemplate template;
private String commentInfoKey="commentInfo";
/**
* 获取缓存评论
* @param subjectCommentID
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public List getCommentInfoCache(long subjectCommentID){
List commentList = new ArrayList();
template.setValueSerializer(new ProtocbufRedisSerializer(CommentSubjectInfo.class));
List list= template.opsForList().range(commentInfoKey+"_"+subjectCommentID, 0, -1);//获取所有
if(list==null)
list= new ArrayList();
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; }

三、 遇到问题
RedisTemplate类型支持不全
默认:

 private  ValueOperations  valueOps ;
private ListOperations listOps ;
private SetOperations setOps ;
private ZSetOperations zSetOps ;

这样在使用上面的方式的时候,如果遇到hash类型,就没有办法设置 setValueSerializer,尝试过用
 @Resource (name= "redisTemplate" )        
private HashOperations subjectCommentNumHash


发现HashOperations类型根本就没有办法获取到RedisTemplate,这样也就没有办法设置setValueSerializer了。再想想是否可以new一个呢,结果发现DefaultHashOperations是包内可见,哎,只有改源码,或者建一个新类 extends DefaultHashOperations了
现在spring-data-redis还不完善,需要改进了。


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
author-avatar
陈苏女士
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有