序列化方式五——ProtoStuff

分类: 365彩票是不是诈骗呢 时间: 2025-10-26 14:22:59 作者: admin 阅读: 5167 点赞: 46
序列化方式五——ProtoStuff

介绍

Protostuff是一个基于Java的高效序列化库,它使用Protocol Buffers(简称protobuf)协议,为Java对象提供高效、灵活且易用的序列化和反序列化方法。Protostuff的主要优势在于其高性能和简单的使用方式,相对于其他序列化库,如JSON或XML,它在处理大量数据时能够显著降低内存使用并提高传输速度。

特点

高效性:Protostuff采用紧凑的二进制编码方式,使得序列化后的字节数量较小,从而提高了传输效率和存储空间利用率。

灵活性:支持动态生成Schema,可以适应不同类型的Java对象,并且能够处理新增或删除字段的情况。此外,Protostuff还支持可插拔的格式,可以方便地集成到各种系统中。

易用性:Protostuff的使用非常简单,只需要在需要序列化的成员上加上Tag注解,并写明顺序即可。同时,官方文档也提供了详细的使用指南和示例代码。

优缺点

优点:

高性能:在速度和内存管理上都表现出色,确保应用在处理大量数据时仍能保持流畅运行。

灵活性高:支持动态生成Schema和可插拔的格式,适应性强。

使用简单:相对于Protobuf等其他序列化库,Protostuff的使用更加简洁明了。

缺点:

需要正确定义Schema:如果没有正确的Schema定义,将无法进行序列化和反序列化操作。

不支持跨版本兼容:当Java对象的字段发生变化时(如新增或删除字段),可能会导致旧版本的字节流无法正常反序列化。因此,在使用Protostuff进行序列化和反序列化时,需要确保Java对象的类定义是稳定的,并且与对应的Schema一致。

与Protobuf的区别

使用简单性:相对于Protobuf需要编写接口定义文件并编译的繁琐操作,Protostuff的使用更加简单直接,只需在需要序列化的成员上添加Tag注解即可。

灵活性:虽然两者都支持动态生成Schema,但Protostuff在灵活性方面表现更佳,支持可插拔的格式以及更广泛的自定义选项。

性能:在性能方面,两者都表现出色。然而,具体性能取决于具体的使用场景和数据结构。一般来说,Protostuff在某些情况下可能具有更高的序列化和反序列化速度。

使用

添加依赖

io.protostuff

protostuff-core

1.8.0

io.protostuff

protostuff-runtime

1.8.0

实体类

package com.zhz.test.serialization.entity;

import io.protostuff.Tag;

import lombok.AllArgsConstructor;

import lombok.Builder;

import lombok.Data;

import lombok.NoArgsConstructor;

/**

* @author zhouhengzhe

*/

@Data

@AllArgsConstructor

@NoArgsConstructor

@Builder

public class ProtoStuffStudent {

@Tag( 1)

private String name;

@Tag(2)

private String studentNo;

@Tag(3)

private int age;

@Tag(4)

private String schoolName;

@Tag(5)

private Address address;

}

package com.zhz.test.serialization.entity;

import io.protostuff.Tag;

import lombok.AllArgsConstructor;

import lombok.Builder;

import lombok.Data;

import lombok.NoArgsConstructor;

/**

* @author zhouhengzhe

*/

@Data

@AllArgsConstructor

@NoArgsConstructor

@Builder

public class Address {

@Tag(1)

private String province;

@Tag(2)

private String city;

}

工具类

package com.zhz.test.serialization.protostuff;

import io.protostuff.LinkedBuffer;

import io.protostuff.ProtostuffIOUtil;

import io.protostuff.Schema;

import io.protostuff.runtime.RuntimeSchema;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

/**

* @author zhouhengzhe

*/

public class ProtobufUtils {

//避免每次序列化都重新申请Buffer空间

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

//缓存类对应的Schema,因为每次都会调用RuntimeSchema.getSchema,所以该方法会比较耗时,

private static Map, Schema> schemaCache = new ConcurrentHashMap<>();

/**

* 序列化方法,把指定对象序列化成字节数组

*/

@SuppressWarnings("unchecked")

public static byte[] serialize(T obj) {

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

Schema schema = getSchema(clazz);

byte[] byteArray = new byte[0];

try {

byteArray = ProtostuffIOUtil.toByteArray(obj, schema, buffer);

} catch (Exception e) {

throw new RuntimeException(e);

}finally {

buffer.clear();

}

return byteArray;

}

/**

* 反序列化方法,把字节数组反序列化成指定Class类型

*/

@SuppressWarnings("unchecked")

public static T deserialize(byte[] data, Class clazz) {

Schema schema = getSchema(clazz);

T obj = schema.newMessage();

ProtostuffIOUtil.mergeFrom(data, obj, schema);

return obj;

}

@SuppressWarnings("unchecked")

private static Schema getSchema(Class clazz) {

Schema schema = (Schema) schemaCache.get(clazz);

if (schema == null) {

schema = RuntimeSchema.getSchema(clazz);

if (schema != null) {

schemaCache.put(clazz, schema);

}

}

return schema;

}

}

测试类

package com.zhz.test.serialization.protostuff;

import com.zhz.test.serialization.entity.Address;

import com.zhz.test.serialization.entity.ProtoStuffStudent;

import org.junit.Test;

import org.springframework.boot.test.context.SpringBootTest;

/**

* @author zhouhengzhe

*/

@SpringBootTest

public class TestProtoStuff {

@Test

public void test() {

ProtoStuffStudent stuffStudent = ProtoStuffStudent

.builder()

.age(3)

.name("lance")

.schoolName("bjut")

.studentNo("2019060544")

.address(Address

.builder()

.city("hunan")

.province("address")

.build())

.build();

//序列化

byte[] serialize = ProtobufUtils.serialize(stuffStudent);

System.out.println(serialize.length);

//反序列化

ProtoStuffStudent deserialize = ProtobufUtils.deserialize(serialize, ProtoStuffStudent.class);

System.out.println(deserialize);

}

}

打个号外

本人新搞的个人项目,有意者可到 DDD用户中台 这里购买

可以学习到的体系

项目完全从0到1开始架构,包含前端,后端,架构,服务器,技术管理相关运维知识!

最佳包名设计,项目分层 破冰CRUD,手撕中间件!

基于MybatisPlus封装属于自己的DDD ORM框架

基于Easyexcel封装属于自己的导入导出组件

oss对象存储脚手架(阿里云,minio,腾讯云,七牛云等)

邮件脚手架

completefuture脚手架

redis脚手架

xxl-job脚手架

短信脚手架

常用工具类等

传统MVC代码架构弊端的解决方案

DDD+CQRS+ES最难架构 结合实际代码的业务场景

多租户单点登录中心

用户中台

消息中心

配置中心

监控设计

程序员的职业规划,人生规划

打工永远没有出路!

打破程序员的35岁魔咒

技术带给你的优势和竞争力【启发】

万物互联网的淘金之路!

技术以外的赚钱路子

可以一起沟通

具体的文章目录

购买链接

DDD用户中台

相关推荐

阴阳师SP烟烟罗🔥技能强度全面解析!超详细分析不容错过!
如何根据excel做数据分析图?
365bet365体育在线

如何根据excel做数据分析图?

📅 09-14 👁️ 3344
知米背单词和扇贝单词哪个好 区别对比详细介绍
注册送365元可提款

知米背单词和扇贝单词哪个好 区别对比详细介绍

📅 07-20 👁️ 7766