什么是序列化?序列化有什么作用?

一、序列化与反序列化
  序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
  序列化使其他代码可以查看或修改,那些不序列化便无法访问的对象实例数据。确切地说,代码执行序列化需要特殊的权限:即指定了 SerializationFormatter 标志的 SecurityPermission。在默认策略下,通过 Internet 下载的代码或 Internet 代码不会授予该权限;只有本地计算机上的代码才被授予该权限。
通常,对象实例的所有字段都会被序列化,这意味着数据会被表示为实例的序列化数据。这样,能够解释该格式的代码有可能能够确定这些数据的值,而不依赖于该成员的可访问性。
  类似地,反序列化从序列化的表示形式中提取数据,并直接设置对象状态,这也与可访问性规则无关。
对于任何可能包含重要的安全性数据的对象,如果可能,应该使该对象不可序列化。如果它必须为可序列化的,请尝试生成特定字段来保存不可序列化的重要数据。如果无法实现这一点,则应注意该数据会被公开给任何拥有序列化权限的代码,并确保不让任何恶意代码获得该权限。
------------------------- 百度百科上面的解释
   我觉得挺好的,我看了很多篇博客,都说的模棱两可,说指堆内存中的java对象数据,通过某种方式把对象存储到磁盘文件中,或者传递给其他网络节点(网络传输)。
说序列化就是把对象存储到磁盘中,我认为这种应该叫做数据持久化,不是叫做序列化。 java对象不能直接存储到磁盘中,或不能直接在网络上传输,需要转化成另一种格式才能,而序列化就是把java对象转化成一种格式的过程,把java对象序列化,变成一种可以存储的形式。
 
  序列化的作用:
    1:对象随着程序的运行而被创建,然后在不可达时被回收,生命周期是短暂的。但是如果我们想长久地把对象的内容保存起来怎么办呢?把它转化为字节序列保存在存储介质上即可。那就需要序列化。
    2:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口
     3:进程间传递对象,Android是基于Linux系统,不同进程之间的java对象是无法传输,所以我们此处要对对象进行序列化,从而实现对象在 应用程序进程 和 ActivityManagerService进程 之间传输。
 
  
  序列化的实现
    1:实现Sericalizable接口,实现Sericalizable接口的时候还要写一个SericalizableUID,这个是版本号,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。如果实现接口的时候,没有给定UID,就会使用默认的UID,当使用默认的UID的时候,jvm每次编译的时候会生成一个UID,当后面程序改了一些代码,再次编译的时候会生成不同的UID,会导致反序列化失败!所以在实现Sericalizable接口的时候,我们自己给定一个固定的UID值,这样就能保证编译完再 反序列化的时候的版本一致性。所以j能不能成功反序列化,就是看对象中的UID和实体中UID是否一致。
    2:实现Externalnalizable接口,在类中实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,在方法中定义类对象自定义的序列化和反序列化操作。这样通过对象输出流和对象输入流的输入输出方法序列化和反序列化对象时会自动调用类中定义的readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法。
    
    对象的实现序列顺序:

      当前类描述的元数据输出为字节序列;【类定义描述、类中属性定义描述】

      超类描述输出为字节序列;【如果超类还有超类,则依次递归,直至没有超类】

      从最顶层超类往下,依次输出各类属性值描述,直至当前类对象属性值。

      即:从下到上描述类定义,从上往下输出属性值。

      当静态变量和transient关键字修饰的变量不能被序列化;

      反序列化时要按照序列化的顺序重构对象:如先序列化A后序列化B,则反序列化时也要先获取A后获取B,否则报错。

 
  序列化漏洞:

    反序列化是一系列安全问题的根源:攻击者能够将恶意数据序列化并存储到数据库或内存中,当应用进行反序列化时,应用会执行到恶意代码。  

    在谷歌内部,这个缺陷被称为“疯狂的小部件 (Mad Gadget)”,外界对它的叫法是 “Java 启示录 (Apocalypse)”。

      所以有一系列的规范来最大化避免: 

       1)对序列化对象执行完整性检查或加密,以防止恶意对象创建或数据篡改;最常见的例子之一就是JWT:JWT由3部分组成:Header,Payload,Verify Signature,最后的签名部分其实就是对数据进行完整性校验的关键部分,用secret对数据部分进行哈希计算,随后检查计算出来的哈希值是否和请求中的JWT签名部分的哈希值相同。若两者一致则认为数据完整性没有被破坏,若两者有差异则说明数据被修改过。

      2)在创建对象之前强制执行严格的类型约束;

      3)隔离反序列化的代码,使其在非常低的特权环境中运行;

      4)记录反序列化的例外情况和失败信息,如:传入的类型不是预期的类型,或者反序列处理引发的例外情况;

      5)限制或监视来自于容器或服务器传入和传出的反序列化网络连接;

      6)监视反序列化,当用户持续进行反序列化时,对用户进行警告。

  

目前JAVA常用的序列化有protobuf,json,xml,Serializable,hessian,kryo。

  protobuf:谷歌公司出的一款开源项目,转码性能高,支持多语言;

  JSON:用途最广泛,序列化方式还衍生了阿里的fastjson,美团的MSON,谷歌的GSON等更加优秀的转码工具。
      优点:使用方便。
      缺点:数据冗长,转码性能一般。

posted on 2021-01-31 15:36  pipizhou  阅读(14930)  评论(2编辑  收藏  举报