介绍
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在某些情况下可能具有更高的序列化和反序列化速度。
使用
添加依赖
<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用户中台