序列化方式五——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用户中台

在 Django 中,ModelSerializer 是 Django REST Framework 中最常用的序列化器之一。它是一个自动化序列化组件,可以帮助我们快速地将一个 Django 模型转换成一个 RESTful API 的响应格式。 具体来说,ModelSerializer 将一个 Django 模型转换成一个 JSON 格式的响应,同时也可以将一个 JSON 格式的请求转换成 Django 模型。这使得我们能够很方便地将 Django 模型与 RESTful API 集成起来。 使用 ModelSerializer 需要进行如下步骤: 1. 创建一个继承自 ModelSerializer 的序列化器类。 2. 在序列化器类中指定模型类和需要序列化的字段。 3. 在视图函数中使用序列化器类进行序列化。 下面是一个示例代码: ```python from rest_framework import serializers from myapp.models import MyModel class MyModelSerializer(serializers.ModelSerializer): class Meta: model = MyModel fields = '__all__' ``` 上述代码中,我们首先导入了 serializers 模块和 MyModel 模型类。然后,我们创建了一个名为 MyModelSerializer 的序列化器类,它继承自 ModelSerializer。在序列化器类的 Meta 类中,我们指定了模型类为 MyModel,并且将 fields 属性设置为 '__all__',表示序列化所有字段。 接下来,在视图函数中使用 MyModelSerializer 进行序列化: ```python from rest_framework import generics from myapp.serializers import MyModelSerializer from myapp.models import MyModel class MyModelList(generics.ListCreateAPIView): queryset = MyModel.objects.all() serializer_class = MyModelSerializer ``` 上述代码中,我们首先导入了 generics 模块、MyModelSerializer 序列化器类和 MyModel 模型类。然后,我们创建了一个名为 MyModelList 的视图类,它继承自 generics.ListCreateAPIView。在视图类中,我们指定了查询集为 MyModel.objects.all(),序列化器类为 MyModelSerializer。 以上就是 ModelSerializer 的基本使用方法。通过 ModelSerializer,我们可以很方便地将一个 Django 模型转换成一个 RESTful API 的响应格式,使得我们能够更加方便地构建 Web 应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhz小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值