当前位置: 首页 > article >正文

序列化方式五——ProtoStuff

介绍

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

特点

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

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

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

优缺点

优点:

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

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

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

缺点:

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

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

与Protobuf的区别

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

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

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

使用

添加依赖

<dependency>
  <groupId>io.protostuff</groupId>
  <artifactId>protostuff-core</artifactId>
  <version>1.8.0</version>
</dependency>
<dependency>
  <groupId>io.protostuff</groupId>
  <artifactId>protostuff-runtime</artifactId>
  <version>1.8.0</version>
</dependency>

实体类

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

    /**
     * 序列化方法,把指定对象序列化成字节数组
     */
    @SuppressWarnings("unchecked")
    public static <T> byte[] serialize(T obj) {
        Class<T> clazz = (Class<T>) obj.getClass();

        Schema<T> 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> T deserialize(byte[] data, Class<T> clazz) {
        Schema<T> schema = getSchema(clazz);
        T obj = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(data, obj, schema);
        return obj;
    }


    @SuppressWarnings("unchecked")
    private static <T> Schema<T> getSchema(Class<T> clazz) {
        Schema<T> schema = (Schema<T>) 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用户中台


http://www.kler.cn/news/326442.html

相关文章:

  • JSON 教程
  • 什么Python库处理大量数据比较快?
  • Oracle 性能优化的高频面试题及答案
  • MySQL和Doris开窗函数LAG执行时的区别
  • PHP入门必看:从基础语法到实际应用,一文掌握Web开发的必备技能!
  • X-Spreadsheet:Web端Excel电子表格工具库
  • “AI+Security”系列第3期(五):AI技术在网络安全领域的本地化应用与挑战
  • 使用 Colly 在 Golang 中进行网页抓取的步骤
  • Rust Web自动化Demo
  • 《动手学深度学习》笔记2.4——神经网络从基础→进阶 (文件读写-保存参数和模型)
  • 堆的数组实现
  • nginx的安装和使用
  • 网页前端开发之Javascript入门篇(1/9):变量
  • 千益畅行,旅游创业新模式的创新与发展
  • 【Python报错已解决】ModuleNotFoundError: No module named ‘tensorflow‘
  • [每周一更]-(第117期):硬盘分区表类型:MBR和GPT区别
  • Windows开发工具使用技巧大揭秘:让编码效率翻倍的秘籍!
  • 软件设计之SSM(3)
  • SpringBoot中各种O的分层模型
  • 16 数组——18. 四数之和 ★★
  • 6种MySQL高可用方案对比分析
  • CleanMyMac X v4.12.1 中文破解版 Mac优化清理工具
  • 10个降低性能的SQL问题及改进措施
  • Leetcode面试经典150题-201.数字范围按位与
  • oracle 分表代码示例
  • FiBiNET模型实现推荐算法
  • qiankun自定义数据通信方案
  • Json files to Excel - Python
  • 【QT】QWidget 重要属性
  • Golang | Leetcode Golang题解之第435题无重叠区间