Springboot集成ProtoBuf的实例

网友投稿 465 2022-08-20


Springboot集成ProtoBuf的实例

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

Springboot集成ProtoBuf

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

1、pom.xml引入相关依赖

com.google.protobuf

protobuf-java

3.5.0

&lthttp://;dependency>

io.protostuff

protostuff-core

1.4.0

io.protostuff

protostuff-runtime

1.4.0

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, Schema>> cachedSchema = new ConcurrentHashMap, Schema>>();

private static Objenesis objenesis = new ObjenesisStd(true);

@SuppressWarnings("unchecked")

private static Schema getSchema(Class cls) {

Schema schema = (Schema) 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 byte[] serializer(T obj) {

Class cls = (Class) obj.getClass();

LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);

try {

Schema 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 deserializer(byte[] bytes, Class clazz) {

try {

T message = (T) objenesis.newInstance(clazz);

Schema 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 bootaWVFvNlfS+IDEA+Windows

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

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

io.protostuff

protostuff-runtime

1.4.0

org.xolstice.maven.plugins

protobuf-maven-plugin

0.5.0

com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier}

grpc-java

compile

compile-custom

写项目对应的.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 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

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

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 官网看到在创建对象,将对象序列化为内存中的字节序列,然后再反序列化的整个过程中相比其他相似技术的性能测试结果图,但是在通用性上会存在局限性,功能相对简单,不适合用来描述数据结构。

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

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 官网看到在创建对象,将对象序列化为内存中的字节序列,然后再反序列化的整个过程中相比其他相似技术的性能测试结果图,但是在通用性上会存在局限性,功能相对简单,不适合用来描述数据结构。

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 官网看到在创建对象,将对象序列化为内存中的字节序列,然后再反序列化的整个过程中相比其他相似技术的性能测试结果图,但是在通用性上会存在局限性,功能相对简单,不适合用来描述数据结构。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java理论基础Stream管道流状态与并行操作
下一篇:java基础理论Stream管道流Map操作示例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~