浅析Java Object Serialization与 Hadoop 序列化

原创 2017年06月12日 20:29:07

浅析Java Object Serialization与 Hadoop 序列化

一,Java Object Serialization
1,什么是序列化(Serialization)
序列化是指将结构化对象转化为字节流以便在网络上传输或者写到磁盘永久存储的过程。反序列化指将字节流转回结构化对象的逆过程。简单的理解就是对象转换为字节流用来传输和保存,字节流转换为对象将对象恢复成原来的状态。

2,序列化(Serialization)的作用
(1)一种持久化机制,把的内存中的对象状态保存到一个文件中或者数据库。
(2)一种通信机制,用套接字在网络上传送对象。
(3)Java远程方法调用(RMI)需要调用对象时,

3,实现了Serializable接口的对象的序列化
在java.io包中,接口Serialization用来作为实现对象串行化的工具 ,只有实现了Serialization的类的对象才可以被序列化。 Serializable接口中没有任何的方法,当一个类声明要实现Serializable接口时,只是表明该类参加序列化协议,而不需要实现任何特殊的方法。
要序列化一个对象,首先要创建OutputStream对象,然后将其封装在一个ObjectOutputStream对象内。此时,调用writeObject()方法将对象序列化并发送给OutputStream。在反序列化时,需要将一个InputStream封装在ObjectInputStream内,然后调用readObject(),得到的结果是一个Object对象,需要进行转型得到最后所需的对象。需要注意的是,在对一个Serializable对象进行反序列化的过程中,没有调用任何构造器,包括缺省的构造器,整个对象都是通过从InputStream中取得数据恢复过来的。对象序列化是面向字节的,因此采用InputStream和OutputStream层次结构。

对Student序列化

package cn.test.serializable;
/**
 * 序列化对象实现Serializable接口
 * @author Young
 * created on 2017-5-25
 */
import java.io.Serializable;

public class Student implements Serializable {
    private String id;
    private String name;

    public Student (String id,String name){
        this.id=id;
        this.name=name;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

序列化

package cn.test.serializable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
 * 序列化
 * @author Young
 * created on 2017-5-25
 */
public class TestSerializable {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Student stu=new Student("201441413110","yang");
        try {
            FileOutputStream out=new FileOutputStream("d:\\student");//创建OutputStream对象
            ObjectOutputStream ob=new ObjectOutputStream(out);//封装在一个ObjectOutputStream对象内
            ob.writeObject(stu);//调用writeObject()方法将对象序列化并发送给OutputStream,保存在d:\\student中
            ob.close();
            out.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

反序列化

package cn.test.serializable;
/**
 * 反序列化
 * @author Young
 * created on 2017-5-25
 */
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class TestDeserializable {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        FileInputStream in;
        Student stu;
        try {
            in = new FileInputStream("d:\\student");
            ObjectInputStream ob=new ObjectInputStream(in);//InputStream封装在ObjectInputStream内
            stu=(Student) ob.readObject();//调用readObject(),得到的结果是一个Object对象,需要进行转型得到最后所需的对象.
            ob.close();
            in.close();
            System.out.println(stu.getId());
            System.out.println(stu.getName());
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

序列化机制写到流中的数据有
1,声明和标记,比如声明使用了序列化协议、序列化协议版本、声明这是一个新的对象、声明这里开始一个新Class、结束标记等。
2,对象所属的类 ,类的长度,
3,SerialVersionUID, 序列化ID,如果没有指定,则会由算法随机生成一个8byte的ID。
4,所有的非transient和非static的属性的个数以及名称。名称长度,属性的值。
这只是简单对象序列化后写到流中的数据。如果是复杂对象序列化就会包含更多的信息。比如引用其他对象作为成员变量,这是会将引用的对象也进行序列化。还有序列化时,只对对象的状态进行保存,而不管对象的方法;当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化。

二,Hadoop 序列化
Hadoop在节点间的内部通讯使用的是RPC,RPC协议把消息翻译成二进制字节流发送到远程节点,远程节点再通过反序列化把二进制流转成原始的信息。
Hadoop使用自己的序列化格式Writable,它绝对紧凑、高速,但不太容易用Java以外的语言进行拓展和使用。
1,Writable接口
Writable接口定义了两个方法:一个将其状态写到DataOutput二进制流,另一个从DataInput二进制流读取其状态:
实现代码

package Hadoop.writable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Writable;
/**
 * hadoop 序列化与反序列化
 * @author Young
 * created by 2017-6-9
 */
public class Serialize {
    public static byte[] serialize(Writable writable) throws IOException{
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream dataout = new DataOutputStream(out);
        try {
            writable.write(dataout);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            dataout.close();
        }
        return out.toByteArray();
    }
    public static byte[] deserialize(Writable writable ,byte[] bytes) throws IOException{
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        DataInputStream datain = new DataInputStream(in);
        try {
            writable.readFields(datain);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            datain.close();
        }
        return bytes;
    }
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        IntWritable intwritable = new IntWritable(20);
        IntWritable newwriatble =new IntWritable();
        byte[] bytes=Serialize.serialize(intwritable);
        deserialize(newwriatble,bytes);
        System.out.println(newwriatble.get());
    }
}

2,Hadoop序列化机制中还包含另外几个重要的接口:WritableComparable、RawComparator 和 WritableComparator
WritableComparable提供类型比较的能力,继承自Writable接口和Comparable接口,其中Comparable进行 类型比较。ByteWritable、IntWritable、DoubleWritable等java基本类型对应的Writable类型,都继承自 WritableComparable。
WritableComparable接口

package org.apache.hadoop.io;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Stable;
import org.apache.hadoop.io.Writable;
@Public
@Stable
public interface WritableComparable<T> extends Writable, Comparable<T> {
}

对于MapReduce来说,类型的比较非常重要,因为中间有个基于键的排序阶段。Hadoop提供了一个具有高效比较能力的RawComparator接口。
RawComparator接口

package org.apache.hadoop.io;
import java.util.Comparator;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Stable;
@Public
@Stable
public interface RawComparator<T> extends Comparator<T> {
    int compare(byte[] arg0, int arg1, int arg2, byte[] arg3, int arg4, int arg5);
}

该接口允许其实现直接比较数据流中的记录,无须先把数据流反序列化为对象,这样避免了新建对象而外的开销。
WritableComparator 是对继承自WritableComparable类的RawComparator类的一个通用实现。提供两个主要功能。1,提供对原始的compare()方法的一个默认实现,该方法能够反序列化将在流中进行比较的对象,并调用对象的compare()方法。2,它充当的是RawComparator实例的工厂,例如为了获得IntWritable的comparator,可以直接调用

RawComparator<IntWritable>comparator=WritableComparator.get(IntWritable.class);

下面是《Hadoop权威指南》的例子

package cn.serialization;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.RawComparator;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparator;
public class TestWritable {
    //序列化
    public static byte[] serialize(Writable writable) throws IOException{
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream dataOut= new DataOutputStream(out);
        writable.write(dataOut);
        dataOut.close();
        return out.toByteArray();
    }
    //反序列化
    public static byte[] deserialize(Writable writable, byte[] bytes) throws IOException{
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        DataInputStream dataIn = new DataInputStream(in);
        writable.readFields(dataIn);
        dataIn.close();
        return bytes;
    }
    public static void main(String[] args) throws IOException {
        @SuppressWarnings("unchecked")
        RawComparator <IntWritable> comparator = WritableComparator.get(IntWritable.class);
        IntWritable w1 = new IntWritable(163);
        IntWritable w2 = new IntWritable(67);
        byte[] b1 = serialize(w1);
        byte[] b2 = serialize(w2);
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(comparator.compare(w1, w2));//WritableComparator的 compare(),w1>w2 -> 1;w1<w2 -> -1 ; w1=w2 -> 0
    System.out.println(comparator.compare(b1,0,b1.length,b2,0,b2.length));
    }
}

三,Hadoop 序列化框架
尽管大多数MapReduce程序使用Writable类型的key,value,但是不是所有MapReduce API 强制使用。事实上,可以使用任何类型,只要能有一种机制将每个类型进行类型与二进制的来回转换。为此Hadoop提供了一个序列化框架来支持,他们在org.apache.hadoop.io.serializer包中,WritableSerialization类是对Writable类型的Serialization实现。
WritableSerialization类

public class WritableSerialization extends Configured implements Serialization<Writable> {...}

Serializer接口
定义了open()接口,序列化接口,close接口

public interface Serializer<T> {
    void open(OutputStream arg0) throws IOException;
    void serialize(T arg0) throws IOException;
    void close() throws IOException;
}

Deserializer接口
定义了open()接口,反序列化接口,close接口

public interface Deserializer<T> {
    void open(InputStream arg0) throws IOException;
    T deserialize(T arg0) throws IOException;
    void close() throws IOException;
}

Serialization接口
定义了一组接口,判断是否支持输入的类,根据输入的类给出序列化接口和反序列化接口

public interface Serialization<T> {
    boolean accept(Class<?> arg0);
    Serializer<T> getSerializer(Class<T> arg0);
    Deserializer<T> getDeserializer(Class<T> arg0);
}

还有几个接口,可以查看API文档

尽管这可以方便我们在MapReduce使用Java类型,比如String,Integer。但是这还是不如Writable高效。
Hadoop中不使用Java Object Serialization的原因
1,Java Object Serialization不够精简,就如本文前面提到的Java Object Serialization序列化后的字节流会包含许多信息,比如类名与对象等。
2,对象在序列化中只存引用,引用可以出现的位置很随机,既可以在序列化的对象前,也可以在其后面,这样就对随机访问和排序造成影响,一旦出错,整个后面的序列化就会全部错误,Writable支持随机访问和排序。因为流中的记录是彼此独立的。
3,.Java序列化每次反序列化都要重新创建对象,内存消耗大,而Writable是可以重用的。

以上内容都是参考网上和《Hadoop权威指南》的,有错请拍砖,帮忙指出。

版权声明:本文为博主原创文章,未经博主允许不得转载。

hadoop深入研究:(十三)——序列化框架

转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/9360075所有源码在github上,https://github.com/la...
  • lastsweetop
  • lastsweetop
  • 2013年07月22日 21:36
  • 7500

22. Dubbo原理解析-编码解码之Serialization接口定义

序列化:dubbo提供了一系列的序列化反序列化对象工具。 Serialization接口定义 @SPI("hessian2") public interface Serialization {...
  • u010311445
  • u010311445
  • 2014年12月03日 20:36
  • 3790

序列化(Serialization)一个对象

1. 序列化的概念         序列化: 将数据结构或对象转换成二进制串的过程,简单理解就是将对象转换为容易传输的格式的过程。 2. 序列化的作用    序列化是为了保存内存中各种对象的状态,并且...
  • xby_869151205
  • xby_869151205
  • 2016年08月06日 17:19
  • 470

C++Boost序列化(Serialization)库教程

一个非常简单的情形 非侵入的版本 可序列化的成员 派生类 指针 数组 STL容器 类的版本 把serialize拆分成save/load 档案 输出档案(archive)类似于输出数据流(stream...
  • fanyun_01
  • fanyun_01
  • 2016年09月30日 09:22
  • 1542

轻量级序列化库boost serialization

对象序列化是项目中最经常看到的场景,因此实现该功能的库也有很多,如:thrift、protobuf、avro,但我觉得这些库都太过沉重,因为他们还提供了rpc的功能,如果只是单纯做对象序列化,boos...
  • FHXPP_27
  • FHXPP_27
  • 2013年01月31日 17:02
  • 7159

java序列化与反序列化以及浅谈一下hadoop的序列化

1、什么是序列化和反序列化 神马是序列化呢,序列化就是把内存中的对象的状态信息,转换成字节序列以便于存储(持久化)和网络传输。(网络传输和硬盘持久化,你没有一定的手段来进行辨别这些字节序列是什么东西...
  • oChenXiaoZuo1
  • oChenXiaoZuo1
  • 2014年08月18日 20:24
  • 1068

Java 和 Hadoop 序列化机制浅讲

序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程(字节流)。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状...
  • zq602316498
  • zq602316498
  • 2015年04月22日 11:42
  • 1105

关于序列化对象.Serializable Object总结.

一个对象需要可实现序列化需要满足以下条件. 1.实现Serializable接口 2.父类必须实现可序列化或者存在默认无参构造函数. 3.类的域变量必须实现可序列化或者定义为transient类...
  • rickylin86
  • rickylin86
  • 2015年12月19日 18:56
  • 2050

hadoop序列化机制与java序列化机制对比

1、采用的方法:       java序列化机制采用的ObjectOutputStream 对象上调用writeObject() 方法; Hadoop 序列化机制调用对象的write() 方法,带一个...
  • zcc_0015
  • zcc_0015
  • 2013年11月17日 22:26
  • 1328

Java之关于Serialization序列化和反序列化

1、什么是序列化和反序列化 Serialization(序列化)是一种将对象以一连串的字节描述的过程; 反序列化deserialization是一种将这些字节重建成一个对象的过程。记住:对象的序列化是...
  • oChangWen
  • oChangWen
  • 2015年12月26日 19:20
  • 651
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:浅析Java Object Serialization与 Hadoop 序列化
举报原因:
原因补充:

(最多只允许输入30个字)