lizongbo at 618119.com 工作,生活,Android,前端,Linode,Ubuntu,nginx,java,apache,tomcat,Resin,mina,Hessian,XMPP,RPC

2008年07月12日

扩展hessian的SerializerFactory以优化支持Protocol Buffers格式的对象

Filed under: Java — 标签:, , — lizongbo @ 18:01

在对  google protobuf简单试用之后(参考: http://618119.com/archives/2008/07/08/100.html),
感觉 google protobuf对对象的序列化非常方便。

google protocolbuffers可以当作一种对对象序列化的方式整合到hessian中。
对于google ProtoBuf 格式的对象,由于没有实现java.io.,默认情况下在hessian中是无法使用的,
不过可以通过启用hessian的对非序列化对象进行支持的参数,
相关代码示例为:
[code]
2Input h2i = new 2Input(bai);
h2i.findSerializerFactory().setAllowNonSerializable(true);//允许非序列化对象
Hessian2Output h2o = new Hessian2Output(bao);
h2o.findSerializerFactory().setAllowNonSerializable(true);//允许非序列化对象

[/code]

在这种情况下,虽然 google protocolbuffers所生成的java对象的构造方法是私有的,
heesian依然可以通过反射方式生成对象。
但是在这种情况下, hessian所序列化出的数据里,携带了大量的无用属性,
这些属性是google ProtoBuf 用来标识对象中的属性状态的,在远程调用的时候,
没有传输的必要。

因此,可以通过扩展hessian的SerializerFactory,使之在传输 格式的对象时,
传输的数据占用尽量少的字节。

扩展的步骤如下:
实现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字节。

没有评论 »

No comments yet.

RSS feed for comments on this post.

Leave a comment

Powered by WordPress