一 何为对象序列化
对象序列化即将一个程序运行时的对象变为二进制流, 又能从二进制流中还原出原来的对象的方法。
对象序列化的用途:
- 可以将对象保存到文件
- 两个进程间通信,交换数据
- 将对象通过网络传输到服务端执行, 执行结果在返回给客户端(远程调用)
二 常见的java对象序列化技术
1。JDK类库中的序列化API
序列化:
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("Person.tmp"));
Person obj = new Person("Tony", 25, "Female", "han");
System.out.println("将Person对象写入到文件Person.tmp中...");
oos.writeObject(obj);
oos.close();
System.out.println("完成!")
反序列化:
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
"Person.tmp"));
obj = (Person) ois.readObject();
System.out.println(obj);
ois.close();
2。Hessian序列化
HessianOutput & HessianInput
序列化代码与Java的类似
3。XStream
XStream是一个开源项目,一套简单实用的类库,用于序列化对象与XML对象之间的相互转换。将XML文件内容解析为一个对象或将一个对象序列化为XML文件
XStream xstream = new XStream();
fromXML(); 用于从xml中将对象解析出来。
toXML(); 用于将对象序列化为xml文件。
String xml = xstream.toXML(joe);
The resulting XML looks like this:
<person>
<firstname>Joe</firstname>
<lastname>Walnes</lastname>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
</person>
- 这几种方法的一个共同点
这些序列化所采用的方法都是遍历对象属性, 采用java反射方法, 获取对象数据, 给对象设置数据. 性能受限于JAVA的反射
三 基于JAVA动态编译的高性能对象序列化技术
- 技术原理
根据对象属性, 动态生成该对象序列化与反序列化的代码,在代码里直接操作对象属性, 然后运行时编译,实例化该类. 负载序列化与反序列化对象.
该技术与上面的方案主要区别是不依赖java的反射机制. 所以性能更高. - 代码实例
要序列化的对象: public class TestDomain implements Serializable { protected int id; protected String name; protected TestDomainChild tdc; protected TestDomain td; ....... }
-
我们可以根据TestDomain的类信息,动态的生成一个专有的Serializer类, 然后运行时编译,实例化. import java.io.IOException; import com.wxy.dynamic.serializer.DynamicSerializerInput; import com.wxy.dynamic.serializer.DynamicSerializerOutput; public class TestDomain_SerializerClass extends AbstractSerializer { public void writeObject(Object object, DynamicSerializerOutput out) throws IOException { TestDomain td = (TestDomain) object; out.writeInt(td.id); out.writeObject(td.name); out.writeObject(td.tdc); out.writeObject(td.data); } public Object readObject(DynamicSerializerInput in) throws IOException { TestDomain td = new TestDomain(); td.id = in.readInt(); td.name = (String) in.readObject(); td.tdc = (TestDomainChild) in.readObject(); td.data = (String) in.readObject(); return td; } }
测试代码 public void testDynamic() throws IOException { SerializerFactory sf = new DefaultSerializerFactory(); TestDomain td = new TestDomain(); td.setId(111); td.setName("sss"); TestDomainChild tdc = new TestDomainChild(); tdc.id = 222; tdc.name = "bbbbbbbbbbb"; td.tdc = tdc; td.td = td; // 序列化对象 ByteArrayOutputStream os = new ByteArrayOutputStream(); DefaultDynamicSerializerOutput out = new DefaultDynamicSerializerOutput(); out.setOutputStream(os); out.setSerializerFactory(sf); out.writeObject(td); //系统会自动生成一个TestDomain专有的Serializer类进行序列化 byte[] buf = os.toByteArray(); //反序列化对象 ByteArrayInputStream is = new ByteArrayInputStream(buf); DefaultDynamicSerializerInput in = new DefaultDynamicSerializerInput(); in.setInputStream(is); in.setSerializerFactory(sf); Object o = in.readObject(); //系统会自动调用已经生成好的TestDomain专有的Serializer类进行反序列化 TestDomain td2 = (TestDomain) o; System.out.println(td2); }
- 优点
性能高出4倍以上. 因为不需要反射. 还可以被JVM的即时编译优化简单的测试代码, 循环1000000次, 后面是执行时间 public void testTime() throws Exception { long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { testHessian(); // 19501 ms //testObjectStream(); // 23455 ms //testDynamic(); // 5086 ms } long use = System.currentTimeMillis() - start; System.out.println(use); }
- 缺点
需要将对象属性设置为protected or public, 这点不是很方便