1. 程式人生 > >Java NIO框架Netty教程(九)

Java NIO框架Netty教程(九)

看到題目,有的同學可能會想,上回不是說過物件傳遞了嗎?是的,只是在《Java NIO框架Netty教程(八)-Object物件傳遞》中,我們只是介紹如何使用Netty提供的編/解碼工具,完成物件的序列化。這節是想告訴你Netty具體是怎麼做的,也許有的同學想自己完成序列化呢?況且,物件的序列化,隨處可用:) 先看怎麼編碼。

@Override
    protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
        ChannelBufferOutputStream
bout = new ChannelBufferOutputStream(dynamicBuffer( estimatedLength, ctx.getChannel().getConfig().getBufferFactory())); bout.write(LENGTH_PLACEHOLDER); ObjectOutputStream oout = new CompactObjectOutputStream(bout); oout.writeObject(msg); oout
.flush(); oout.close(); ChannelBuffer encoded = bout.buffer(); encoded.setInt(0, encoded.writerIndex() - 4); return encoded; }

其實你早已經應該想到了,在Java中對物件的序列化自然跑不出ObjectOutputStream了。Netty這裡只是又做了一層包裝,在流的開頭增加了一個4位元組的標誌位。所以,Netty宣告,該編碼和解碼的類必須配套使用,與單純的ObjectIntputStream不相容。

		* An encoder which serializes a Java object into a {@link ChannelBuffer}.<br />
		* <p><br />
		* Please note that the serialized form this encoder produces is not<br />
		* compatible with the standard {@link ObjectInputStream}.&nbsp; Please use<br />
		* {@link ObjectDecoder} or {@link ObjectDecoderInputStream} to ensure the<br />
		* interoperability with this encoder.</p>

那麼解碼,自然是先解析出多餘的4位,然後再通過ObjectInputStream解析。

關於Java物件序列化的細節問題,不在文字討論的範圍內,不過不知您是否感興趣試試自己寫一個呢?所謂,多動手嘛。

/**
 * Object編碼類
 * 
 * @author lihzh
 * @alia OneCoder
 * @blog http://www.coderli.com
 */
public class MyObjEncoder implements ChannelDownstreamHandler {

	@Override
	public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e)
			throws Exception {
		// 處理收發資訊的情形
		if (e instanceof MessageEvent) {
			MessageEvent mEvent = (MessageEvent) e;
			Object obj = mEvent.getMessage();
			if (!(obj instanceof Command)) {
				ctx.sendDownstream(e);
				return;
			}
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(out);
			oos.writeObject(obj);
			oos.flush();
			oos.close();
			ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
			buffer.writeBytes(out.toByteArray());
			e.getChannel().write(buffer);
		} else {
			// 其他事件,自動流轉。比如,bind,connected
			ctx.sendDownstream(e);
		}
	}
}
/**
 * Object解碼類
 * 
 * @author lihzh
 * @alia OneCoder
 * @blog http://www.coderli.com
 */
public class MyObjDecoder implements ChannelUpstreamHandler {

	@Override
	public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e)
			throws Exception {
		if (e instanceof MessageEvent) {
			MessageEvent mEvent = (MessageEvent) e;
			if (!(mEvent.getMessage() instanceof ChannelBuffer)) {
				ctx.sendUpstream(mEvent);
				return;
			}
			ChannelBuffer buffer = (ChannelBuffer) mEvent.getMessage();
			ByteArrayInputStream input = new ByteArrayInputStream(buffer.array());
			ObjectInputStream ois = new ObjectInputStream(input);
			Object obj = ois.readObject();
			Channels.fireMessageReceived(e.getChannel(), obj);
		}
	}
}

怎麼樣,是不是也好用?所謂,模仿,學以致用。

不過,提醒一下大家,這個實現裡有很多硬編碼的東西,切勿模仿,只是為了展示Object,編解碼的處理方式和在Netty中的應用而已。