netty 是 开源的基于java的网络通信框架,其中java对象的传输,netty使用的是java原生的序列化/反序列化实现的,而Kryo是性能更好的java序列化框架,能否让netty和kryo结合,实现高性能的数据通信呢?下面就是如何实现。
首先,模仿Netty自带的ObjectEncoder,写一个kryo序列化的ObjectEncoder:
import static org.jboss.netty.buffer.ChannelBuffers.dynamicBuffer;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferOutputStream;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Output;
public class ObjectKryoEncoder extends OneToOneEncoder {
private static final byte[] LENGTH_PLACEHOLDER = new byte[4];
@Override
protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
ChannelBufferOutputStream bout =
new ChannelBufferOutputStream(dynamicBuffer(
4096, ctx.getChannel().getConfig().getBufferFactory()));
bout.write(LENGTH_PLACEHOLDER);
Kryo kryo = new Kryo();
Output output = new Output(bout);
kryo.writeClassAndObject(output, msg);
output.flush();
output.close();
ChannelBuffer encoded = bout.buffer();
encoded.setInt(0, encoded.writerIndex() - 4);
return encoded;
}
}
接下来,模仿Netty自带的ObjectDecoder,写一个kryo序列化的ObjectDecoder:
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferInputStream;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
public class ObjectKryoDecoder extends LengthFieldBasedFrameDecoder {
public ObjectKryoDecoder() {
this(10485760);
}
public ObjectKryoDecoder(int maxObjectSize) {
super(maxObjectSize, 0, 4, 0, 4);
}
@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
ChannelBuffer frame = (ChannelBuffer) super.decode(ctx, channel, buffer);
if (frame == null) {
return null;
}
Kryo kryo = new Kryo();
Input input = null;
try {
input = new Input(new ChannelBufferInputStream(frame));
return kryo.readClassAndObject(input);
} finally {
input.close();
}
}
}
以上的Encoder和Decoder都是kryo序列化的版本,将其注入ChannelPipelineFactory 中即可:
ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new ObjectKryoDecoder());
pipeline.addLast("encoder", new ObjectKryoEncoder());
pipeline.addLast("handler", new TimeClientHandler3());
return pipeline;
}
});
......