Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)(二)

简介: Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)(二)

三、Protobuf序列化


介绍

protobuf—Github地址、protobuf-java


介绍:Protobuf 出自于 Google,性能还比较优秀,也支持多种语言,同时还是跨平台的。就是在使用中过于繁琐,因为你需要自己定义 IDL 文件和生成对应的序列化代码。这样虽然不然灵活,但是,另一方面导致 protobuf 没有序列化漏洞的风险。


Protobuf 包含序列化格式的定义、各种语言的库以及一个 IDL 编译器。正常情况下你需要定义 proto 文件,然后使用 IDL 编译器编译成你需要的语言。


正常流程:定义proto文件 -> 使用proto编译工具编译得到Java类 -> 使用该类来进行序列化与反序列化。


快速开始

引入依赖


<!--      protobuf  -->
<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.21.1</version>
</dependency>


使用步骤


1、首先安装proto的转换工具


下载地址



安装配置好对应的path路径,测试下命令:


protoc --version


安装这个proto工具的目的是将对应自己编写的.proto文件转为一个Java类,使用这个Java类即可进行序列化与反序列化。


在一个.proto文件中可以写多个结构体都是可以的。


2、编写proto文件


使用ProtoBuf序列化数据—可查看对应protobuf对应java的类型


syntax = "proto3";
option java_package = "com.changlu.serialize.protobuf";
option java_outer_classname = "DemoModel";
message User {
  string name = 1;
  uint32 age = 2;
}
message Message {
  uint32 message_type = 1;
}


java_package:表示目标生成的包名路径。

java_outer_classname:目标生成的工具类名称。

说明:若是觉得自己编写比较麻烦,那么我们可以自己先定义Java实体类,然后使用IDEA的插件将这个实体类转为对应proto的struct类型。


插件名称:pojo to proto;protobuf插件安装使用


3、准备好proto文件了之后,我们就要开始生成对应的工具类了


当前路径在main/proto/xxx下,我们想要输出到对应的main/java/com/changlu/serialize/protobuf/xxx中:



接着我们输入命令:


# -I:我自己编写的.proto 文件的位置。 
# --java out 输出位置会以完整包名的形式出输出,我指定的是上级目录的java中,此时配合proto文件里的com.changlu.xxx,即可输出到我想要的目录下
# ./subscribeReq.proto:当前需要编译成java的proto文件名。
protoc -I=./ --java_out=../java ./User.proto



ok,此时我们就有了这个工具类DemoModel,对应的User、Message的实体类都在这个DemoModel类中有了,对于序列化与反序列化操作也在这个DemoModel中进行。


测试



//测试ProtoBuf
testProtobufSerialzize();


public void testProtobufSerialzize(){
    //准备实体类
    DemoModel.User.Builder userBuilder = DemoModel.User.newBuilder();
    userBuilder.setAge(18);
    userBuilder.setName("changlu");
    DemoModel.User user = userBuilder.build();
    System.out.println("=====开始序列化:Protobuf=====");
    System.out.println("开始进行序列化");
    long startTime = System.nanoTime();
    //序列化
    byte[] data = user.toByteArray();
    long endTime = System.nanoTime();
    System.out.println("  序列化时间为:" + (endTime - startTime) / 1000000000.0 + "秒");
    System.out.println("  序列化后的内容为:" + new String(data));
    System.out.println("  序列化后的长度为:" + data.length);
    System.out.println("开始进行反序列化");
    startTime = System.nanoTime();
    //反序列化
    try {
        System.out.println("  反序列化后得到的对象为:" + DemoModel.User.parseFrom(data));
    } catch (InvalidProtocolBufferException e) {
        throw new RuntimeException("Serialization failed");
    }
    endTime = System.nanoTime();
    System.out.println("  反序列化时间为:" + (endTime - startTime) / 1000000000.0 + "秒");
    System.out.println("=====结束序列化:Protobuf=====" + "\n");
}




四、ProtoStuff


介绍

protostuff-github


由于 Protobuf 的易用性,它的哥哥 Protostuff 诞生了。


protostuff 基于 Google protobuf,但是提供了更多的功能和更简易的用法。虽然更加易用,但是不代表 ProtoStuff 性能更差。


快速开始
<!--      protobufstuff  -->
<dependency>
    <groupId>io.protostuff</groupId>
    <artifactId>protostuff-core</artifactId>
    <version>1.7.4</version>
</dependency>
<dependency>
    <groupId>io.protostuff</groupId>
    <artifactId>protostuff-runtime</artifactId>
    <version>1.7.4</version>
</dependency>
<!--      protobufstuff  -->



package com.changlu.serialize;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
/**
 * @Description: ProtoStuffSer序列化工具
 * @Author: changlu
 * @Date: 11:33 AM
 */
public class ProtoStuffSerializer implements Serializer{
    //DEFAULT_BUFFER_SIZE:512
    //每次序列化时使用缓冲区
    private static final LinkedBuffer BUFFER = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
    public byte[] serialize(Object obj) {
        Class<?> clazz = obj.getClass();
        Schema schema = RuntimeSchema.getSchema(clazz);
        byte[] bytes;
        try {
            //序列化
            bytes = ProtostuffIOUtil.toByteArray(obj, schema, BUFFER);
        }finally {
            BUFFER.clear();
        }
        return bytes;
    }
    public <T> T deserialize(byte[] bytes, Class<T> clazz) {
        Schema<T> schema = RuntimeSchema.getSchema(clazz);
        //反序列化
        T obj = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(bytes, obj, schema);
        return obj;
    }
}



测试



//测试ProtoStuff
testSerialize(new ProtoStuffSerializer(), rpcResponse);



说明:这个序列化算法的反序列化是最快的目前来看。


五、hessian


介绍

hessian 是一个轻量级的,自定义描述的二进制 RPC 协议。hessian 是一个比较老的序列化实现了,并且同样也是跨语言的。


dubbo RPC 默认启用的序列化方式是 hessian2 ,但是,Dubbo 对 hessian2 进行了修改,不过大体结构还是差不多。


快速开始
<!--      hessian  -->
<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>4.0.65</version>
</dependency>



package com.changlu.serialize;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
 * @Description: Hessian序列化
 * @Author: changlu
 * @Date: 12:38 PM
 */
public class HessianSerializer implements Serializer{
    @Override
    public byte[] serialize(Object obj) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();){
            HessianOutput hessianOutput = new HessianOutput(baos);
            //序列化
            hessianOutput.writeObject(obj);
            return baos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("Serialization failed");
        }
    }
    @Override
    public <T> T deserialize(byte[] bytes, Class<T> clazz) {
        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);){
            HessianInput hessianInput = new HessianInput(bais);
            //反序列化
            return clazz.cast(hessianInput.readObject(clazz));
        } catch (IOException e) {
            throw new RuntimeException("Serialization failed");
        }
    }
}



测试



//测试Hession
testSerialize(new HessianSerializer(), rpcResponse);



总结


Kryo 是专门针对 Java 语言序列化方式并且性能非常好,如果你的应用是专门针对 Java 语言的话可以考虑使用,并且 Dubbo 官网的一篇文章中提到说推荐使用 Kryo 作为生产环境的序列化方式。


其他跨语言的序列化方式包含:Protobuf、 ProtoStuff、hessian如果有跨语言需求的话可以考虑使用,其他还包含Thrift,Avro 这些。

相关文章
|
26天前
|
Java
让星星⭐月亮告诉你,自定义定时器和Java自带原生定时器
定时器是一种可以设置多个具有不同执行时间和间隔的任务的工具。本文介绍了定时器的基本概念、如何自定义实现一个定时器,以及Java原生定时器的使用方法,包括定义定时任务接口、实现任务、定义任务处理线程和使用Java的`Timer`与`TimerTask`类来管理和执行定时任务。
43 3
|
2月前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
51 2
|
1天前
|
安全 Java 编译器
JDK 10中的局部变量类型推断:Java编程的简化与革新
JDK 10引入的局部变量类型推断通过`var`关键字简化了代码编写,提高了可读性。编译器根据初始化表达式自动推断变量类型,减少了冗长的类型声明。虽然带来了诸多优点,但也有一些限制,如只能用于局部变量声明,并需立即初始化。这一特性使Java更接近动态类型语言,增强了灵活性和易用性。
78 53
|
26天前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
20 1
|
2月前
|
Oracle Java 关系型数据库
Linux下JDK环境的配置及 bash: /usr/local/java/bin/java: cannot execute binary file: exec format error问题的解决
如果遇到"exec format error"问题,文章建议先检查Linux操作系统是32位还是64位,并确保安装了与系统匹配的JDK版本。如果系统是64位的,但出现了错误,可能是因为下载了错误的JDK版本。文章提供了一个链接,指向Oracle官网上的JDK 17 Linux版本下载页面,并附有截图说明。
Linux下JDK环境的配置及 bash: /usr/local/java/bin/java: cannot execute binary file: exec format error问题的解决
|
2月前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
62 11
|
2月前
|
监控 Java 大数据
【Java内存管理新突破】JDK 22:细粒度内存管理API,精准控制每一块内存!
【9月更文挑战第9天】虽然目前JDK 22的确切内容尚未公布,但我们可以根据Java语言的发展趋势和社区的需求,预测细粒度内存管理API可能成为未来Java内存管理领域的新突破。这套API将为开发者提供前所未有的内存控制能力,助力Java应用在更多领域发挥更大作用。我们期待JDK 22的发布,期待Java语言在内存管理领域的持续创新和发展。
|
2月前
|
Oracle Java 关系型数据库
【颠覆性升级】JDK 22:超级构造器与区域锁,重塑Java编程的两大基石!
【9月更文挑战第6天】JDK 22的发布标志着Java编程语言在性能和灵活性方面迈出了重要的一步。超级构造器和区域锁这两大基石的引入,不仅简化了代码设计,提高了开发效率,还优化了垃圾收集器的性能,降低了应用延迟。这些改进不仅展示了Oracle在Java生态系统中的持续改进和创新精神,也为广大Java开发者提供了更多的可能性和便利。我们有理由相信,在未来的Java编程中,这些新特性将发挥越来越重要的作用,推动Java技术不断向前发展。
|
2月前
|
Kubernetes Cloud Native Java
探索未来编程新纪元:Quarkus带你秒建高性能Kubernetes原生Java应用,云原生时代的技术狂欢!
Quarkus 是专为 Kubernetes 设计的全栈云原生 Java 框架,凭借其轻量级、快速启动及高效执行特性,在 Java 社区脱颖而出。通过编译时优化与原生镜像支持,Quarkus 提升了应用性能,同时保持了 Java 的熟悉度与灵活性。本文将指导你从创建项目、编写 REST 控制器到构建与部署 Kubernetes 原生镜像的全过程,让你快速上手 Quarkus,体验高效开发与部署的乐趣。
38 0
|
3月前
|
Java API Apache
JDK8到JDK24版本升级的新特性问题之在Java中,HttpURLConnection有什么局限性,如何解决
JDK8到JDK24版本升级的新特性问题之在Java中,HttpURLConnection有什么局限性,如何解决
下一篇
无影云桌面