1.什么是序列化和反序列化
序列化:将对象转化为字节流。以便在网络上传输或者写在磁盘上进行永久存储。
反序列化:将字节流转回成对象。
序列化在分布式数据处理的两个领域曾经出现:进程间通信、永久存储。
Hadoop中多个节点进程间的通信通过远程过程调用(Remote Procedure Call, RPC)实现。
2. Hadoop的序列化
Hadoop的序列化不采用Java的序列化,而是实现了自己的序列化机制。在Hadooop序列化机制中,用户可以复用对象,这就减少了Java对象的分配和回收,从而提高了应用效率。
Hadoop通过Writable接口实现序列化机制,但是没有提供比较的功能,所以和Java中的Comparable接口合并,提供一个接口WritableComparable。
public interface Writable{
void write(DataOutput out)throws IOException; // 状态写入到DataOutput二进制流
void readFields(DataInput in)throws IOException; // 从DataInput二进制流中读取状态
}
public interface WritableComparable<T>extends Writable, Comparable<T>P{
}
3. 举个例子
3.1 案例分析
功能需求:序列化Person对象,并将序列化的对象反序列化出来。
实现步骤:
- 序列化对象类implements WritableComparable
- 属性:既可以采用Hadoop模型,也可以采用Java模型
- 实现write方法接口:将对象转换为字节流并写入到输出流out中。
a. 如果属性是Hadoop类型的:name.write(out)
b. 如果属性是Java类型的:out.write(name) - 实现readFields接口:从输入流in中读取字节流并反序列化对象
a. 如果属性是Hadoop类型的:name.readFields(int)
b. 如果属性是Java类型的:in.readFields(name) - 实现Compare To 方法接口
- setter方法:采用Java类型的属性,方便客户操作
- 构造方法
- 实现to String/ hashCode/ equals方法
3.2 代码实现
Person类:
package Serialize;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class Person implements WritableComparable<Person> {
private Text name = new Text(); //名字
private IntWritable age = new IntWritable(); //年龄
private Text sex = new Text(); //性别
public Person(String name, int age, String sex){
this.name.set(name);
this.age.set(age);
this.sex.set(sex);
}
public Person(){}
@Override
public int compareTo(Person o) {
int result = 0;
int compl = name.compareTo(o.name);
if (compl != 0){
return compl;
}
int comp2 = age.compareTo(o.age);
if (comp2 != 0){
return comp2;
}
int comp3 = sex.compareTo(o.sex);
if (comp3 != 0){
return comp3;
}
return result;
}
@Override
public void write(DataOutput out) throws IOException {
name.write(out);
age.write(out);
sex.write(out);
}
@Override
public void readFields(DataInput in) throws IOException {
name.readFields(in);
age.readFields(in);
sex.readFields(in);
}
@Override
public String toString(){
return "Person[name = "+ name + ", age = "+age+", sex = "+sex+"]";
}
}
序列化工具类:
package Serialize;
import org.apache.hadoop.io.Writable;
import java.io.*;
public class HadoopSerializationUtil {
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 void deserialize(Writable writable, byte[] bytes)throws Exception{
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
DataInputStream datain = new DataInputStream(in);
writable.readFields(datain);
datain.close();
}
}
Test:
package Serialize;
import javax.jnlp.PersistenceService;
public class Test {
public static void main(String[] args) throws Exception{
Person person = new Person("songyanan", 18, "girl");
byte[] values = HadoopSerializationUtil.serialize(person);
Person p = new Person();
HadoopSerializationUtil.deserialize(p, values);
System.out.println(p);
}
}
结果截图:
4. 反思
对序列化感兴趣的同学,可以研究一下Hadoop的序列化与Java序列化的区别。