聊聊分布式架构——序列化和反序列化

目录

序列化与反序列化

为什么需要序列化

常见的序列化方式

java的序列化示例

transient排除序列化

Java序列化的简单总结


序列化与反序列化
  • 序列化就是把对象的状态信息转化为可存储或传输的形式过程,也就是把对象转化为字节序列的过程称为对象的序列化。

  • 反序列化是序列化的逆向过程,把字节数组反序列化为对象,把字节序列恢复为对象的过程称为对象的反序列化。

为什么需要序列化
  1. 数据持久化:序列化使得对象可以被保存到磁盘或数据库中,以便在程序重新启动时恢复状态。这在许多应用中很有用,如保存应用设置、用户数据、游戏进度等。

  2. 跨平台通信:不同的计算机和编程语言可能使用不同的数据表示形式。序列化可以将数据转换为通用的格式(如JSON或XML),从而实现跨平台和跨语言的通信,使不同系统之间能够互相交换数据。

  3. 远程调用和分布式系统:在分布式系统中,远程服务器上的方法可能需要接收和返回对象。序列化可以将对象编码为字节流,以便在网络上传输,然后在另一端进行反序列化。这使得远程过程调用(RPC)和分布式系统更容易实现。

  4. 消息传递:在消息传递系统中,消息通常以序列化的形式进行传输。这在消息队列、微服务架构和事件驱动系统中非常常见。

  5. 缓存:序列化可以用于将对象缓存到内存中,以加快访问速度。缓存可以存储序列化的数据,而不必在每次访问时重新创建对象。

  6. 复制和克隆:通过序列化,可以轻松地创建对象的副本或克隆,而不必手动复制每个字段。

  7. 数据传输和备份:在数据传输和备份过程中,序列化可以帮助将数据从一个位置传输到另一个位置,或创建数据的备份。

常见的序列化方式

随着分布式架构、微服务架构的普及。服务与服务之间的通信成了最基本的需求。而对于序列化的要求也逐渐迫切,衍生出了一系列具有高效数据传输性能的热点技术。下面列举了一些常见的序列化方式:

  1. Java 序列化

    • Java 提供了内置的序列化机制,通过实现 java.io.Serializable 接口可以使一个 Java 对象可序列化。可以使用 ObjectOutputStream 将对象序列化为字节流,然后使用 ObjectInputStream 进行反序列化。这种方式是 Java 特有的,不适用于与其他编程语言通信。

  2. JSON(JavaScript Object Notation)序列化

    • JSON 是一种文本格式,用于表示结构化数据。它支持序列化和反序列化对象数据,并且是跨语言通信的常见方式。许多编程语言都有用于处理 JSON 数据的库。例如,在 Java 中,可以使用 Gson、Jackson 等库将对象转换为 JSON 字符串,然后再将 JSON 字符串还原为对象。

  3. XML(eXtensible Markup Language)序列化

    • XML 是一种标记语言,常用于表示和交换数据。类似于 JSON,XML 也可以用于序列化和反序列化对象数据。在 Java 中,可以使用 JAXB(Java Architecture for XML Binding)库来实现 XML 序列化和反序列化。

  4. Protocol Buffers(protobuf)序列化

    • Protocol Buffers 是一种二进制格式,用于高效地序列化和反序列化数据。它支持多种编程语言,并且具有较小的数据大小和较高的性能。Google 的 Protocol Buffers 是最知名的实现之一。

  5. MessagePack 序列化

    • MessagePack 是一种二进制序列化格式,类似于 JSON,但更轻量和高效。它支持多种编程语言,并且适用于高性能应用程序。

  6. Thrift 序列化

    • Apache Thrift 是一种跨语言的序列化框架,支持多种数据传输格式,包括二进制、JSON 和 XML。它用于构建高性能、跨语言的分布式系统。

  7. Avro 序列化

    • Apache Avro 是一种数据序列化系统,设计用于大规模数据处理。它支持 JSON 格式,具有架构演化的能力,适用于大数据处理和数据仓库。

java的序列化示例

首先,假设我们有一个名为Person的Java类,我们想要将其序列化和反序列化:

public class Person implements Serializable {private String name;private int age;
​public Person(String name, int age) {this.name = name;this.age = age;}
​// Getter and Setter methods
​@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + '}';}
}

接下来,我们将演示如何将Person对象序列化为字节流,并从字节流中反序列化回Person对象:

public class SerializationExample {public static void main(String[] args) {// 创建一个Person对象Person person = new Person("Alice", 30);
​try {// 序列化到文件FileOutputStream fileOutputStream = new FileOutputStream("person.ser");ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);objectOutputStream.writeObject(person);objectOutputStream.close();fileOutputStream.close();System.out.println("Person对象已经被序列化到person.ser文件");
​// 从文件中反序列化回Person对象FileInputStream fileInputStream = new FileInputStream("person.ser");ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);Person deserializedPerson = (Person) objectInputStream.readObject();objectInputStream.close();fileInputStream.close();
​System.out.println("从person.ser文件中反序列化的Person对象:");System.out.println(deserializedPerson);
​} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}

上述示例中,我们首先创建了一个Person对象,然后使用ObjectOutputStream将其序列化为名为person.ser的文件。接着,我们使用ObjectInputStream从该文件中读取数据,并将其反序列化为一个新的Person对象。

需要注意的是,要使类可序列化,需要实现Serializable接口,这是Java序列化机制的要求。此外,对象的字段也必须是可序列化的,或者将它们标记为transient以排除序列化。

transient排除序列化

Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

然而,有时候您可能需要绕过transient机制,将某些transient字段也包含在对象的序列化表示中,这可以使用自定义的writeObjectreadObject方法来实现。这样可以实现对transient字段的手动序列化和反序列化控制。

class MyClass implements Serializable {private transient String transientField = "I'm transient";private String nonTransientField = "I'm not transient";
​// 使用writeObject手动序列化transientFieldprivate void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject(); // 调用默认的序列化方法
​// 手动序列化transientFieldout.writeObject(transientField);}
​// 使用readObject手动反序列化transientFieldprivate void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject(); // 调用默认的反序列化方法
​// 手动反序列化transientFieldtransientField = (String) in.readObject();}
​@Overridepublic String toString() {return "transientField: " + transientField + ", nonTransientField: " + nonTransientField;}
}
​
public class Main {public static void main(String[] args) throws IOException, ClassNotFoundException {MyClass obj = new MyClass();
​// 将对象序列化到文件FileOutputStream fileOut = new FileOutputStream("object.ser");ObjectOutputStream out = new ObjectOutputStream(fileOut);out.writeObject(obj);out.close();fileOut.close();
​// 从文件中反序列化对象FileInputStream fileIn = new FileInputStream("object.ser");ObjectInputStream in = new ObjectInputStream(fileIn);MyClass deserializedObj = (MyClass) in.readObject();in.close();fileIn.close();
​System.out.println(deserializedObj); // 输出序列化后的对象,transientField不再是null}
}

在上面的示例中,transientField被标记为transient,但我们使用自定义的writeObjectreadObject方法手动序列化和反序列化了它。这使得transientField可以包含在序列化表示中,并且在反序列化后保留其值。请注意,在自定义的writeObject方法中,我们首先调用out.defaultWriteObject()以调用默认的序列化方法,然后手动序列化transientField。在自定义的readObject方法中,我们首先调用in.defaultReadObject()以调用默认的反序列化方法,然后手动反序列化transientField

ArrayList中的Object[]就是transient修饰的,利用writeObject绕过transient机制,目的是为了更高效地尽可能精简地返回数组数据。

     /*** The array buffer into which the elements of the ArrayList are stored.* The capacity of the ArrayList is the length of this array buffer. Any* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* will be expanded to DEFAULT_CAPACITY when the first element is added.*/transient Object[] elementData; // non-private to simplify nested class access
​
​/*** Save the state of the <tt>ArrayList</tt> instance to a stream (that* is, serialize it).** @serialData The length of the array backing the <tt>ArrayList</tt>*             instance is emitted (int), followed by all of its elements*             (each an <tt>Object</tt>) in the proper order.*/private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException{// Write out element count, and any hidden stuffint expectedModCount = modCount;s.defaultWriteObject();
​// Write out size as capacity for behavioural compatibility with clone()s.writeInt(size);
​// Write out all elements in the proper order.for (int i=0; i<size; i++) {s.writeObject(elementData[i]);}
​if (modCount != expectedModCount) {throw new ConcurrentModificationException();}}
Java序列化的简单总结
  1. Java序列化只是针对对象的状态进行保存,至于对象中的方法,序列化不关心

  2. 当一个父类实现了序列化,那么子类会自动实现序列化,不需要显示实现序列化接口

  3. 当一个对象的实例变量引用了其他对象,序列化这个对象的时候会自动把引用的对象也进 行序列化(实现深度克隆)

  4. 当某个字段被申明为 transient 后,默认的序列化机制会忽略这个字段

  5. 被申明为transient的字段,如果需要序列化,可以添加两个私有方法:writeObject 和 readObject

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/124992.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker快速搭建漏洞靶场指南

user: admin passwrod&#xff1a;password 查看容器是否已开启&#xff1a; 最常见漏洞&#xff1a; 防护级别提高后&#xff1a; 更改防护级别&#xff1a; 复现vulhub漏洞靶场&#xff1a; 开启&#xff1a; 一个是漏洞类型一个是真实的漏洞靶场。

去雨去雪去雾算法之本地与服务器的TensorBoard使用教程

在进行去雨去雾去雪算法实验时&#xff0c;需要注意几个参数设置&#xff0c;num_workers只能设置为0&#xff0c;否则会报各种稀奇古怪的错误。 本地使用TensorBoard 此外&#xff0c;发现生成的文件是events.out.tfevents格式的&#xff0c;查询了一番得知该文件是通过Tens…

asp.net core mvc 文件上传,下载,预览

//文件上传用到了IformFile接口 1.1文件上传视图 <form action"/stu/upload" method"post" enctype"multipart/form-data"><input type"file" name"img" /><input type"submit" value"上传&…

Lwip的接收邮箱大小的影响

LwIP&#xff08;Lightweight IP&#xff09;是一个用于嵌入式系统的轻量级的TCP/IP协议栈&#xff0c;它支持UDP和其他网络协议。 接收邮箱大小 在LwIP中&#xff0c;UDP接收邮箱的大小对系统性能和可靠性有一定影响。 首先&#xff0c;UDP接收邮箱的大小决定了可以同时接收…

联想Lenovo 威6 15-ITL(82F2)原厂Win10系统

lenovo联想原装出厂系统 自带所有驱动、出厂主题壁纸LOGO、Office办公软件、联想电脑管家等预装程序 下载链接&#xff1a;https://pan.baidu.com/s/1darORHmIyAXkD7HvKRNHNw?pwddh6e 所需要工具&#xff1a;16G或以上的U盘 文件格式&#xff1a;ISO 文件大小&#xff1a;11.…

(三)激光线扫描-中心线提取

光条纹中心提取算法是决定线结构光三维重建精度以及光条纹轮廓定位准确性的重要因素。 1. 光条的高斯分布 激光线条和打手电筒一样,中间最亮,越像周围延申,光强越弱,这个规则符合高斯分布,如下图。 2. 传统光条纹中心提取算法 传统的光条纹中心提取算法有 灰度重心法、…

SpringCloud + SpringGateway 解决Get请求传参为特殊字符导致400无法通过网关转发的问题

title: “SpringCloud SpringGateway 解决Get请求传参为特殊字符导致400无法通过网关转发的问题” createTime: 2021-11-24T10:27:5708:00 updateTime: 2021-11-24T10:27:5708:00 draft: false author: “Atomicyo” tags: [“tomcat”] categories: [“java”] description: …

stm32 - 中断/定时器

stm32 - 中断/定时器 概念时钟树定时器类型基准时钟&#xff08;系统时钟&#xff09;预分频器 - 时基单元CNT计数器 - 时基单元自动重装寄存器 - 时基单元基本定时器结构通用定时器计数器模式内外时钟源选择 定时中断基本结构时序预分频器时序计数器时序 例子通用定时器 - 内部…

日常工作报告生成器微信小程序源码 支持日报,周报,月报,年终终结

相信大家上班都会有做工作报告的情况吧 那么这款小程序就是大家的福音了 只要输入你的工作内容或者岗位自动生成你的工作报告 支持报,周报,月报,年终终结 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88391810 源码下载2&#xff1a;评论留言或私信…

代码随想录算法训练营第五十七天 | 动态规划 part 15 | 392.判断子序列、115.不同的子序列

目录 392.判断子序列思路代码 115.不同的子序列思路代码 392.判断子序列 Leetcode 思路 dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度为dp[i][j]递推公式&#xff1a; 初始化&#xff1a;为0遍历顺序&#xff…

Zabbix4自定义脚本监控MySQL数据库

一、MySQL数据库配置 1.1 创建Mysql数据库用户 [rootmysql ~]# mysql -uroot -p create user zabbix127.0.0.1 identified by 123456; flush privileges; 1.2 添加用户密码到mysql client的配置文件中 [rootmysql ~]# vim /etc/my.cnf.d/client.cnf [client] host127.0.0.1 u…

微服务技术栈-Gateway服务网关

文章目录 前言一、为什么需要网关二、Spring Cloud Gateway三、断言工厂和过滤器1.断言工厂2.过滤器3.全局过滤器4.过滤器执行顺序 四、跨域问题总结 前言 在之前的文章中我们已经介绍了微服务技术中eureka、nacos、ribbon、Feign这几个组件&#xff0c;接下来将介绍另外一个组…