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; } }); ......