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

标签: java 序列化 序列化 | 发表时间:2014-08-19 04:24 | 作者:oChenXiaoZuo1
出处:http://blog.csdn.net

1、什么是序列化和反序列化

神马是序列化呢,序列化就是把 内存中的对象的状态信息,转换成 字节序列以便于存储(持久化)和网络传输。(网络传输和硬盘持久化,你没有一定的手段来进行辨别这些字节序列是什么东西,有什么信息,这些字节序列就是垃圾)。

反序列化就是将收到 字节序列或者是硬盘的持久化数据,转换成 内存中的对象

2、JDK的序列化

JDK的序列化只有实现了serializable接口就能实现序列化与反序列化,但是记得一定要加上序列化版本ID serialVersionUID 
这个是识别序列化的之前那个类的到底是哪一个?我们显示这个序列化版本ID的目的就是为了:

1) 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

2) 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

java的序列化算法要考虑到下面这些东西:

◆将对象实例相关的类元数据输出。

◆递归地输出类的超类描述直到不再有超类。

◆类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。

◆从上至下递归输出实例的数据

所以java的序列化确实很强大,序列化后得到的信息也很详细,所以反序列化就so easy.
但是这样做也有它的坏处,序列化后很占内存,所以不一定详细就是好处,简单有时也是不错的。
在hadoop中,hadoop实现了一套自己的序列化框架,hadoop的序列化相对于JDK的序列化来说是比较简洁的。在集群中信息的传递主要就是靠这些序列化的字节序列来传递的所以更快速度更小的容量就变得非常地重要了。
说了太多的废话,还是扯回JDK的序列化吧。下面我们看一下在JDK中式如何实现序列化的。

首先我们有一个需要序列化的类如下(必须实现serializable接口)
import java.io.Serializable;

public class Block implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private int id;
	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Block(int id, String name) {
		this.id = id;
		this.name = name;
	}

}

下面我们来测试一下序列化的结果:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TestSerializable {
	public static void main(String[] args) throws IOException,
			ClassNotFoundException {
		//将序列化化的数据写到文件out里面(持久化)
		FileOutputStream fos = new FileOutputStream("./out");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		for (int i = 0; i < 100; i++) {
			Block b = new Block(i, "B"+i);
			oos.writeObject(b);
		}
		oos.flush();
		oos.close();
		
		//读出一个序列化的对象的字节序列(^..^)就是反序列化
		FileInputStream fis = new FileInputStream("./out");
		ObjectInputStream ois = new ObjectInputStream(fis);
		Block b2 = (Block) ois.readObject();
		ois.close();
		System.out.println(b2.getName());
	}
}

测试的结果:(取出第一个对象的name)
B0
生成一百个对象的持久化数据的大小是:1.60 KB (1,643 字节)一个对象平均16个字节,该类只有两个字段一个是int,一个字符串但是字符串的长度为2,所以我们可以感受到这冗余还是挺大的。

3、hadoop的序列化

hadoop的序列化的特点是:

1、紧凑:由于带宽是集群中信息传递的最宝贵的资源所以我们必须想法设法缩小传递信息的大小,hadoop的序列化就为了更好地坐到这一点而设计的。

2、对象可重用:JDK的反序列化会不断地创建对象,这肯定会造成一定的系统开销,但是在hadoop的反序列化中,能重复的利用一个对象的readField方法来重新产生不同的对象。

3、可扩展性:当前hadoop的序列化有多中选择
*可以利用实现hadoop的Writable接口。
*使用开源的序列化框架protocol Buffers,Avro等框架。
     我们可以注意到的是hadoop2.X之后是实现一个叫YARN的云操作系统,所有应用(如mapreduce,或者其他spark实时或者离线的计算框架都可以运行在YARN上),YARN还负责对资源的调度等等。
YARN的序列化就是用Google开发的序列化框架protocol Buffers,proto目前支持支持三种语言C++,java,Python所以RPC这一层我们就可以利用其他语言来做文章,满足其他语言开发者的需求。
我屮艸芔茻,扯得有点远。
回到hadoop原生的序列化,hadoop原生的序列化类需要实现一个叫Writeable的接口,类似于serializable接口。
还有hadoop也为我们提供了几个序列化类,他们都直接或者间接地实现了Writable接口。如:IntWritable,LongWritable,Text等等。
实现Writable接口必须实现两个方法:write(DataOutputStream out);readField(DataInputStream in)方法。
下面是一个hadoop的序列化例子:
package hadoop;

import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.junit.Test;

public class Testhadoop_serializable_writable {
	@Test
	public void serializable() throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		DataOutputStream dataOut = new DataOutputStream(out);
		FileOutputStream fos = new FileOutputStream("./hadoop_out");
		for (int i = 0; i < 10; i++) {
			Text t1 = new Text(String.valueOf(i));
			Text t2 = new Text("mw");
			MyWritable mw = new MyWritable(t1,t2);
			mw.write(dataOut);
		}
		dataOut.close();
		fos.write(out.toByteArray());
		fos.flush();
		fos.close();

		FileInputStream fis = new FileInputStream("./hadoop_out");
		DataInputStream dis = new DataInputStream(fis);
		for (int i = 0; i < 10; i++) {
			MyWritable mw = new MyWritable(new Text(), new Text());
			mw.readFields(dis);
			System.out.println(mw.getId() + " " + mw.getName());
		}

	}
}

class MyWritable implements Writable {
	private Text id;
	private Text name;

	public MyWritable(Text id, Text name) {
		super();
		this.id = id;
		this.name = name;
	}

	public synchronized Text getId() {
		return id;
	}

	public synchronized void setId(Text id) {
		this.id = id;
	}

	public synchronized Text getName() {
		return name;
	}

	public synchronized void setName(Text name) {
		this.name = name;
	}

	@Override
	public void write(DataOutput out) throws IOException {
		id.write(out);
		name.write(out);
	}

	@Override
	public void readFields(DataInput in) throws IOException {
		id.readFields(in);
		name.readFields(in);
	}

}

我们可以看到我们实现的自己序列化类MyWritable。他有两个字段都是Text,Text是hadoop自带的序列化类,可以看做字符串(类似吧)吧?!
write()和readField()用到的是回调函数,将流(DataOutputStream DataInputStream)写出,或者读出,都是用到回调函数(hook(钩子))。

上面的运行结果如下:
生成的字节序列:

命令行结果:

完!





















作者:oChenXiaoZuo1 发表于2014-8-18 20:24:06 原文链接
阅读:0 评论:0 查看评论

相关 [java 序列化 序列化] 推荐:

java序列化java.io.Externalizable

- - Java - 编程语言 - ITeye博客
这次我们讲的是控制对象的序列化和反序列化. 控制序列化就是有选择的序列化对象,而不是把对象的所以内容都序列化,前篇我们的例子中介绍了transit变量和类变量(static)不被序列化,现在我们还有一种更为灵活的控制对象序列化和反序列方法,可以在序列化过程中储存其他非this对象包含的数据. 我们现在再来介绍一个接口 java.io.Externalizable.

JAVA 反序列化攻击

- - OneAPM 博客
Java 反序列化攻击漏洞由. FoxGlove 的最近的一篇博文爆出,该漏洞可以被黑客利用向服务器上传恶意脚本,或者远程执行命令. 由于目前发现该漏洞存在于 Apache commons-collections, Apache xalan 和 Groovy 包中,也就意味着使用了这些包的服务器(目前发现有WebSphere, WebLogic,JBoss),第三方框架(Spring,Groovy),第三方应用(Jenkins),以及依赖于这些服务器,框架或者直接/间接引用这些包的应用都会受到威胁,这样的应用的数量会以百万计.

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

- - CSDN博客云计算推荐文章
1、什么是序列化和反序列化. 神马是序列化呢,序列化就是把 内存中的对象的状态信息,转换成 字节序列以便于存储(持久化)和网络传输. (网络传输和硬盘持久化,你没有一定的手段来进行辨别这些字节序列是什么东西,有什么信息,这些字节序列就是垃圾). 反序列化就是将收到 字节序列或者是硬盘的持久化数据,转换成 内存中的对象.

讲解Java中的序列化

- - IT江湖
serialVersionUID的作用. serialVersionUID适用于JAVA的序列化机制. 简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的. 在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException.

理解Java对象序列化

- - 博客 - 伯乐在线
来源: jiangshapub 的博客( @jiangshapub). 关于Java序列化的文章早已是汗牛充栋了,本文是对我个人过往学习,理解及应用Java序列化的一个总结. 此文内容涉及Java序列化的基本原理,以及多种方法对序列化形式进行定制. 在撰写本文时,既参考了 Thinking in Java, Effective Java,JavaWorld,developerWorks中的相关文章和其它网络资料,也加入了自己的实践经验与理解,文、码并茂,希望对大家有所帮助.

对Java序列化早作防备(译)

- - BlogJava_首页
本文是 IBM developerWorks中的 一篇文章,介绍了不使用加密与签章技术,如何防止对不可信数据输入的解序列化. (2013.01.17最后更新).     Java序列化允许开发者将Java对象保存为二进制格式,以便将该对象持久化到一个文件中或将其在网络中进行传递. 远程方法调用(RMI)使用序列化作为客户端与服务器端之间的通信媒介.

java 序列化 serializable接口 serialVersionUID

- - 互联网 - ITeye博客
如果一个类实现了serializable接口,那么就会要求一个serialVersionUID. 序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类. 如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException.

Java序列化理解与总结

- - CSDN博客编程语言推荐文章
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长. 但在现实应用中,就可能要求在JVM停止运行之后能够保存指定的对象,并在将来重新读取被保存的对象. Java对象序列化就能够帮助我们实现该功能.

java反序列化工具ysoserial分析

- - WooYun知识库
关于java反序列化漏洞的原理分析,基本都是在分析使用 Apache Commons Collections这个库,造成的反序列化问题. 然而,在下载老外的 ysoserial工具并仔细看看后,我发现了许多值得学习的知识. 不同反序列化 payload玩法. 灵活运用了反射机制和动态代理机制构造POC.

(反)序列化

- - Java - 编程语言 - ITeye博客
本章关注对象序列化API,它提供了一个框架,用来将对象编码成字节流,并从字节流中重新构建对象. “将对象编码成字节流”被称作对象序列化,相反的处理过程被称作反序列化. 序列化技术为远程通信提供了标准的线路级对象表示法,也为JavaBeans组件结构提供了标准的持久化数据格式. 第七十四条:谨慎地实现Serializable接口.