在对 google protobuf简单试用之后(参考: http://618119.com/archives/2008/07/08/100.html),
感觉 google protobuf对对象的序列化非常方便。
google protocolbuffers可以当作一种对对象序列化的方式整合到hessian中。
对于google ProtoBuf 格式的对象,由于没有实现java.io.Serializable,默认情况下在hessian中是无法使用的,
不过可以通过启用hessian的对非序列化对象进行支持的参数,
相关代码示例为:
[code]
Hessian2Input h2i = new Hessian2Input(bai);
h2i.findSerializerFactory().setAllowNonSerializable(true);//允许非序列化对象
Hessian2Output h2o = new Hessian2Output(bao);
h2o.findSerializerFactory().setAllowNonSerializable(true);//允许非序列化对象
[/code]
在这种情况下,虽然 google protocolbuffers所生成的java对象的构造方法是私有的,
heesian依然可以通过反射方式生成对象。
但是在这种情况下, hessian所序列化出的数据里,携带了大量的无用属性,
这些属性是google ProtoBuf 用来标识对象中的属性状态的,在远程调用的时候,
没有传输的必要。
因此,可以通过扩展hessian的SerializerFactory,使之在传输 google ProtoBuf 格式的对象时,
传输的数据占用尽量少的字节。
扩展的步骤如下:
实现ProtoBufSerializerFactory和ProtoBufDeserializer及ProtoBufSerializer
然后在HessianInput(或Hessian2Input),HessianOutput(或Hessian2Output)中调用addFactory方法。
ProtoBufSerializerFactory.java的代码为:
[code]
package com.lizongbo.hessian.protobuf;
import com.caucho.hessian.io.*;
import com.google.protobuf.*;
/**
*
* <p>Title: google protobuf 对象的序列化工厂</p>
*
* <p>Description: 扩展对google protobuf格式的对象的序列化 </p>
*
* <p>Copyright: Copyright (c) 2008</p>
*
* <p>Company: 618119.com </p>
*
* @author lizongbo
* @version 1.0
*/
public class ProtoBufSerializerFactory extends AbstractSerializerFactory {
private static final ProtoBufSerializerFactory instance = new
ProtoBufSerializerFactory();
Serializer serializer = new ProtoBufSerializer();
public Deserializer getDeserializer(Class cl) throws
HessianProtocolException {
if (Message.class.isAssignableFrom(cl)) {
try {
return new ProtoBufDeserializer(cl);
} catch (NoSuchMethodException ex) {
ex.printStackTrace();
return null;
}
}
return null;
}
public Serializer getSerializer(Class cl) throws HessianProtocolException {
if (Message.class.isAssignableFrom(cl)) {
return serializer;
}
return null;
}
public static ProtoBufSerializerFactory getInstance() {
return instance;
}
}
[/code]
ProtoBufSerializer.java的代码为:
[code]
package com.lizongbo.hessian.protobuf;
import java.io.*;
import com.caucho.hessian.io.*;
import com.google.protobuf.Message;
public class ProtoBufSerializer extends AbstractSerializer {
public void writeObject(Object obj, AbstractHessianOutput out) throws
IOException {
if (obj == null) {
out.writeNull();
} else {
Class cl = obj.getClass();
if (out.addRef(obj)) {
return;
}
int ref = out.writeObjectBegin(cl.getName());
if (ref < -1) {
out.writeString("lizongbo");
out.writeBytes(((Message) obj).toByteArray());
out.writeMapEnd();
} else {
if (ref == -1) {
out.writeInt(1);
out.writeString("lizongbo");
out.writeObjectBegin(cl.getName());
}
out.writeBytes(((Message) obj).toByteArray());
}
}
}
}
[/code]
ProtoBufDeserializer.java的代码为:
[code]
package com.lizongbo.hessian.protobuf;
import java.io.*;
import com.caucho.hessian.io.*;
import com.google.protobuf.Message;
public class ProtoBufDeserializer extends AbstractDeserializer {
private Class _cl;
private Message.Builder _constructor;
public ProtoBufDeserializer(Class cl) throws NoSuchMethodException {
_cl = cl;
try {
_constructor = (Message.Builder) cl.getMethod("newBuilder").invoke(new
Object[0]);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public Class getType() {
return _cl;
}
public Object readMap(AbstractHessianInput in) throws IOException {
int ref = in.addRef(null);
byte[] initValue = null;
while (!in.isEnd()) {
String key = in.readString();
if (key.equals("lizongbo")) {
initValue = in.readBytes();
} else {
in.readString();
}
}
in.readMapEnd();
Object value = create(initValue);
in.setRef(ref, value);
return value;
}
public Object readObject(AbstractHessianInput in, String[] fieldNames) throws
IOException {
int ref = in.addRef(null);
byte[] initValue = null;
for (int i = 0; i < fieldNames.length; i++) {
String key = fieldNames[i];
if (key.equals("lizongbo")) {
initValue = in.readBytes();
} else {
in.readObject();
}
}
Object value = create(initValue);
in.setRef(ref, value);
return value;
}
private Object create(byte[] initValue) throws IOException {
if (initValue == null || initValue.length < 1) {
throw new IOException(_cl.getName() + " expects name.");
}
try {
return _constructor.mergeFrom(initValue).build();
} catch (Exception e) {
throw new IOExceptionWrapper(e);
}
}
}
[/code]
调用的代码为:
[code]
Hessian2Input h2i = new Hessian2Input(bai);
h2i.findSerializerFactory().addFactory(ProtoBufSerializerFactory.getInstance());
h2i.findSerializerFactory().setAllowNonSerializable(true);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
////OutputStream bao2 = new HessianDebugOutputStream(bao, dbg); //增加调试输出,如果不需要调试,则屏蔽该行即可。
Hessian2Output h2o = new Hessian2Output(bao);
h2o.findSerializerFactory().addFactory(ProtoBufSerializerFactory.getInstance());
h2o.findSerializerFactory().setAllowNonSerializable(true);
[/code]
在我封装的hessian数据包,传递一个QQuser对象的情况下
优化前 收到的一个数据包长:259(有其它额外信息)
优化后收到的数据包长:79(有其它额外信息)
Protocol Buffers格式的byteArray得到的字节长度,17
对比可知节约259-(79-17)=197字节。
标签: google protobuf, Hessian, Serializable
或分享到 Google Buzz
或
或