Springboot集成ProtoBuf的实例

目录
  • Springboot集成ProtoBuf
    • 1、pom.xml引入相关依赖
    • 2、新建序列化工具类ProtoBufUtil.java
    • 3、新建实体类User.java
    • 4、使用方式
  • ProtoBuf+Java+Springboot+IDEA应用
    • 什么是Protobuf
    • 应用环境
    • 开发环境

Springboot集成ProtoBuf

ProtoBuf是一种序列化和解析速度远高于JSON和XML的数据格式,项目中使用了CouchBase作为缓存服务器,从数据库中拿到数据后通过protobuf序列化后放入CouchBase作为缓存,查询数据的时候解压并反序列化成数据对象,下面是ProtoBuf的具体使用方法

1、pom.xml引入相关依赖

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.5.0</version>
</dependency>
<dependency>
    <groupId>io.protostuff</groupId>
    <artifactId>protostuff-core</artifactId>
    <version>1.4.0</version>
</dependency>
<dependency>
    <groupId>io.protostuff</groupId>
    <artifactId>protostuff-runtime</artifactId>
    <version>1.4.0</version>
</dependency>

2、新建序列化工具类ProtoBufUtil.java

package com.xrq.demo.utils; 
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.objenesis.Objenesis;
import org.springframework.objenesis.ObjenesisStd;
 
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
 
/**
 * ProtoBufUtil 转换工具类
 * 
 * @author XRQ
 *
 */
public class ProtoBufUtil {
    private static Logger log = LoggerFactory.getLogger(ProtoBufUtil.class);
    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();
 
    private static Objenesis objenesis = new ObjenesisStd(true);
 
    @SuppressWarnings("unchecked")
    private static <T> Schema<T> getSchema(Class<T> cls) {
        Schema<T> schema = (Schema<T>) cachedSchema.get(cls);
        if (schema == null) {
            schema = RuntimeSchema.createFrom(cls);
            if (schema != null) {
                cachedSchema.put(cls, schema);
            }
        }
        return schema;
    }
 
    public ProtoBufUtil() {
    }
 
    @SuppressWarnings({ "unchecked" })
    public static <T> byte[] serializer(T obj) {
        Class<T> cls = (Class<T>) obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            Schema<T> schema = getSchema(cls);
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } catch (Exception e) {
            log.error("protobuf序列化失败");
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            buffer.clear();
        }
    }
 
    public static <T> T deserializer(byte[] bytes, Class<T> clazz) {
        try {
            T message = (T) objenesis.newInstance(clazz);
            Schema<T> schema = getSchema(clazz);
            ProtostuffIOUtil.mergeFrom(bytes, message, schema);
            return message;
        } catch (Exception e) {
            log.error("protobuf反序列化失败");
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
 
}

3、新建实体类User.java

注:重点是@Tag标签需要按照顺序往下排,如果需要新增字段,只能接着往下排,不能改变已存在的标签序号

package com.xrq.demo.bo; 
import java.io.Serializable;
import java.util.Date;  
import io.protostuff.Tag;
 
/**
 * 用户信息类
 * 
 * @ClassName: User
 * @author XRQ
 * @date 2019年4月30日
 */
public class User implements Serializable
{
    private static final long serialVersionUID = 1L;
 
    // 用户ID
    @Tag(1)
    private int userId;
 
    // 用户类型
    @Tag(2)
    private int userTypeId;
 
    // 用户名 
    @Tag(3)
    private String userName;
 
    // 创建时间
    @Tag(4)
    private Date createDateTime; 
    public int getUserId()
    {
 
        return userId;
    }
 
    public void setUserId(int userId)
    {
 
        this.userId = userId;
    }
 
    public int getUserTypeId()
    {
 
        return userTypeId;
    }
 
    public void setUserTypeId(int userTypeId)
    {
 
        this.userTypeId = userTypeId;
    }
 
    public String getUserName()
    {
 
        return userName;
    }
 
    public void setUserName(String userName)
    {
 
        this.userName = userName;
    }
 
    public Date getCreateDateTime()
    {
 
        return createDateTime;
    }
 
    public void setCreateDateTime(Date createDateTime)
    {
 
        this.createDateTime = createDateTime;
    }
}

4、使用方式

User user = new User();
user.setUserId(1);
user.setUserTypeId(1);
user.setUserName("XRQ");
user.setCreateDateTime(new Date());
//序列化成ProtoBuf数据结构
byte[] userProtoObj= ProtoBufUtil.serializer(userInfo)
 
//ProtoBuf数据结构反序列化成User对象
User newUserObj = ProtoBufUtil.deserializer(userProtoObj, User.class))

ProtoBuf+Java+Springboot+IDEA应用

什么是Protobuf

1.Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准;

2.Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式;

3.形式为.proto结尾的文件;

应用环境

近期接触公司的网约车接口对接项目,第三方公司限定了接口的数据用protobuf格式序列化后,通过AES128加密后传输。

开发环境

Java+Spring boot+IDEA+Windows

新建Spring boot项目 在IDEA开发工具中安装protobuf插件

添加配置maven依赖(可能一开始自己的项目中存在固有的配置,不要删除,在对应的地方添加下面的配置即可,不需要修改)

<dependency>
	<groupId>io.protostuff</groupId>
	<artifactId>protostuff-runtime</artifactId>
	<version>1.4.0</version>
</dependency>
<plugin>
	<groupId>org.xolstice.maven.plugins</groupId>
	<artifactId>protobuf-maven-plugin</artifactId>
	<version>0.5.0</version>
	<configuration>
	<protocArtifact>
		com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier}
	</protocArtifact>
	<pluginId>grpc-java</pluginId>
	</configuration>
	<executions>
		<execution>
			<goals>
				<goal>compile</goal>
                <goal>compile-custom</goal>
            </goals>
        </execution>
    </executions>
</plugin>

写项目对应的.proto文件(这里贴一部分代码)

// 版本号
syntax = "proto2";
// 打包路径
option java_package="XXX1";
// Java文件名
option java_outer_classname="XXX2";
// 属性信息
message BaseInfo {
	// 公司标识
	required string CompanyId       = 1;
	// 公司名称
	required string CompanyName     = 2;
    // 操作标识
	required uint32 Flag            = 3;
	// 更新时间
	required uint64 UpdateTime      = 4;
}

.proto文件存在项目路径

生成.java文件方式(点击项目中的.proto文件,找到对应的maven依赖,双击标识2对应的protobuf:compile文件)

运行成功之后在对应路径下查看生成的.java文件

生成的Java文件即可使用(如果在业务中.proto文件很大,生成的Java大小超出IDEA默认的2.5M,生成的Java文件将被IDEA误认为不是Java文件,导致生成的Java文件不可使用,这时需要修改IDEA的配置文件,将默认的大小修改,重启IDEA即可) 进行数据序列化

List<BaseInfo> baseInfoList = baseInfoMapper.selectAll();
XXX2.OTIpcList.Builder listBuilder = XXX2.OTIpcList.newBuilder();
XXX2.OTIpc.Builder otipcBuilder = XXX2.OTIpc.newBuilder();
otipcBuilder.setCompanyId(ProjectConstant.COMPANY_ID);
otipcBuilder.setSource(ProjectConstant.COMPANY_SOURCE);
otipcBuilder.setIPCType(OTIpcDef.IpcType.baseInfoCompany);
for(int i=0;i<baseInfoList .size();i++){
	try{
		XXX2.BaseInfo.Builder baseInfoBuilder = XXX2.BaseInfo.newBuilder();
		baseInfoBuilder .setCompanyId(baseInfoList .get(i).getCompanyid());
		baseInfoBuilder .setCompanyName(baseInfoList .get(i).getCompanyname());
		baseInfoBuilder .setFlag(baseInfoList .get(i).getFlag());
		baseInfoBuilder .setUpdateTime(baseInfoList .get(i).getUpdatetime());
		for(int j=0;j<10;j++) {
			otipcBuilder.addBaseInfo(baseInfoBuilder .build());
		}
	}
	catch (Exception e){
		LoggerUtils.info(getClass(),e.getMessage());
	}
}
listBuilder.addOtpic(otipcBuilder);

进行数据AES128位加密

public static String sendScreate(OTIpcDef.OTIpcList.Builder listBuilder) {
        String screateKeyString = getSecretKey();
        String screateKey = screateKeyString.split(";")[1];
        String screateValue = screateKeyString.split(";")[0];
        OTIpcDef.OTIpcList list = listBuilder.build();
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        try {
            list.writeTo(output);
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] data = null;
        try{
            byte[] keyByte = new byte[screateValue.length()/2];
            for(int j=0;j<screateValue.length()/2;j++) {
                byte b = (byte) ((Integer.valueOf(String.valueOf(screateValue.charAt(j*2)), 16) << 4) |
                        Integer.valueOf(String.valueOf(screateValue.charAt(j*2+1)), 16));
                keyByte[j] = b;
		}
		Key secretKey= new SecretKeySpec(keyByte,"AES");
		Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
		Cipher cipher= Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
		cipher.init(Cipher.ENCRYPT_MODE, secretKey);
		data = cipher.doFinal(output.toByteArray());
		sendPostJSON(screateKey, data);
		return "success";
	} catch(Exception e){
		e.printStackTrace();
	}
	return null;
}

小结一下:经验证,Protobuf 序列化相比XML,JSON性能更好,在Protobuf 官网看到在创建对象,将对象序列化为内存中的字节序列,然后再反序列化的整个过程中相比其他相似技术的性能测试结果图,但是在通用性上会存在局限性,功能相对简单,不适合用来描述数据结构。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • SpringBoot使用protobuf格式的接口方式

    SpringBoot使用protobuf格式的接口 建立SpringBoot项目,pom.xml内容如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:sche

  • 浅谈序列化之protobuf与avro对比(Java)

    最近在做socket通信中用到了关于序列化工具选型的问题,在调研过程中开始趋向于用protobuf,可以省去了编解码的过程.能够实现快速开发,且只需要维护一份协议文件即可. 但是调研过程中发现了protobuf的一些弊端,比如需要生成相应的文件类,和业务绑定太紧密,所以在看了AVRO之后发现它完美解决了这个问题. 下面记录下对这两种序列化工具的入门与测评. 一.protobuf基本操作 protobuf简介: Protocol Buffers (a.k.a., protobuf) are Goo

  • Protobuf的简要介绍及使用详解

    一.protobuf的应用场景 在官方文档中可以看到 protocol buffers 是一种语言无关.平台无关.可扩展的序列化结构数据的方法,它可用于(数据)通信协议.数据存储等. Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍).更快(20 ~ 100倍).更为简单. 可以看到protobuf 与json相比具有 压缩比高 .解压缩速度更快的优点 二.protobuf的使用 protobuf在使用上较为

  • Springboot集成ProtoBuf的实例

    目录 Springboot集成ProtoBuf 1.pom.xml引入相关依赖 2.新建序列化工具类ProtoBufUtil.java 3.新建实体类User.java 4.使用方式 ProtoBuf+Java+Springboot+IDEA应用 什么是Protobuf 应用环境 开发环境 Springboot集成ProtoBuf ProtoBuf是一种序列化和解析速度远高于JSON和XML的数据格式,项目中使用了CouchBase作为缓存服务器,从数据库中拿到数据后通过protobuf序列化后

  • SpringBoot集成swagger的实例代码

    Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件.本文简单介绍了在项目中集成swagger的方法和一些常见问题.如果想深入分析项目源码,了解更多内容,见参考资料. Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步.Swagger 让部署管理和使用功能强大的API从未如此简单. 对于

  • springboot集成activemq的实例代码

    ActiveMQ ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位. 特性 多种语言和协议编写客户端.语言: Java,C,C++,C#,Ruby,Perl,Python,PHP.应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP

  • SpringBoot集成Druid的实例代码

    快速开始 依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.17</version> </dependency> 如果需要配置日志: <dependency> <groupId>log4j</groupId>

  • SpringBoot集成Elasticsearch过程实例

    1. 准备工作 需要提前安装好Elasticsearch,访问地址:http://127.0.0.1:9200/ 得到以下结果,得到cluster_name,下面配置使用. { "name" : "O8GslS3", "cluster_name" : "docker-cluster", "cluster_uuid" : "pviTqfXtR3GtnxF-Po-_aA", "ve

  • SpringBoot 集成Kaptcha实现验证码功能实例详解

    在一个web应用中验证码是一个常见的元素.不管是防止机器人还是爬虫都有一定的作用,我们是自己编写生产验证码的工具类,也可以使用一些比较方便的验证码工具.在网上收集一些资料之后,今天给大家介绍一下kaptcha的和springboot一起使用的简单例子. 准备工作: 1.你要有一个springboot的hello world的工程,并能正常运行. 2.导入kaptcha的maven: <!-- https://mvnrepository.com/artifact/com.github.penggl

  • springboot Mongodb的集成与使用实例详解

    说说springboot与大叔lind.ddd的渊源 Mongodb在Lind.DDD中被二次封装过(大叔的.net和.net core),将它当成是一种仓储来使用,对于开发人员来说只公开curd几个标准的接口即可,而在springboot框架里,它与大叔lind有些类似之处,同样是被二次封装了,开发人员只需要关注自己的业务即可,而标准的curd操作完成由springboot帮助我们来实现,一般地,我们会设计一个与实体对象的接口仓储,让它去继承mongo的标准接口,然后在springboot的依

  • springboot集成fastDfs过程代码实例

    这篇文章主要介绍了springboot集成fastDfs过程代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 pom.xml 引入依赖 <dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.26.1-RELEASE</vers

  • springboot集成微软teams的实例代码

    前言 最近做了一个有关微软的平台teams开发,在国内用微软teams聊天工具的少之又少,整个亚洲也没什么开发的实例,官方文档写的有点乱,在没有第三方支持下开发有点头疼.需求是做一个管理后台跟teams打通,支持各种通告发送,以及撤回.没时间具体些,用的东西丢在上面用上的可以参考. 添加依赖 <dependency> <groupId>com.microsoft.graph</groupId> <artifactId>microsoft-graph</

  • SpringBoot集成MyBatis的分页插件PageHelper实例代码

    昨天给各位总结了本人学习springboot整合mybatis第一阶段的一些学习心得和源码,主要就算是敲了一下SpringBoot的门儿,希望能给各位的入门带给一点儿捷径,今天给各位温习一下MyBatis的分页插件PageHelper和SpringBoot的集成,它的使用也非常简单,开发更为高效.因为PageHelper插件是属于MyBatis框架的,所以相信很多哥们儿都已经用烂了,下面带着各位吃一下回头草. 首先说说MyBatis框架的PageHelper插件吧,它是一个非常好用的分页插件,通

随机推荐