原文: http://netty.io/wiki/user-guide-for-4.x.html
聊一下用POJO代替ByteBuf
到目前为止我们点评的所有代码实例都使用ByteBuf作为主要的消息格式. 在这一章节, 我们将改进TIME协议的客户端和服务端去使用POJO代替ByteBuf.
使用POJO在你的ByteBuf是显尔易见的; 通过从处理单元中分离从ByteBuf提取信息的代码你的处理单元更容易维护和重用性更高. 在TIME的实例中, 我们只是读一个32位整型数字, 这个不是直接使用ByteBuf的主要问题. 然而, 你将发现分离你实现的一个真实的通信协议是很有必要的.
首先, 让我们定义一个新的类型就叫UnixTime.
package io.netty.example.time; import java.util.Date; public class UnixTime { private final int value; public UnixTime() { this((int) (System.currentTimeMillis() / 1000L + 2208988800L)); } public UnixTime(int value) { this.value = value; } public int value() { return value; } @Override public String toString() { return new Date((value() - 2208988800L) * 1000L).toString(); } }
我们调整一下TimeDecoder去产生一个UnixTime而不是ByteBuf.
@Override protected Object decode(ChannelHandlerContext ctx, ByteBuf in, MessageList<Object> out) { if (in.readableBytes() < 4) { return; } out.add(new UnixTime(buffer.readInt()); }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageList<Object> msgs) { UnixTime m = (UnixTime) msgs.get(0); System.out.println(m); ctx.close(); }更简单和优雅, 对吗? 同样的技术可以应用的服务端. 让我们再更新一下TimeServerHandler:
@Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { ChannelFuture f = e.getChannel().write(new UnixTime()); f.addListener(ChannelFutureListener.CLOSE); }现在唯一缺少的一块是编码器, 这是一个ChannelOutboundHandler的实现, 他将UnixTime转换为ByteBuf. 比写一个解码器还要简单因为当编码消息时不需要处理分包和装配的问题.
package io.netty.example.time; public class TimeEncoder extends ChannelOutboundHandlerAdapter { @Override public void write(ChannelHandlerContext ctx, MessageList<Object> msgs, ChannelPromise promise) { MessageList<ByteBuf> out = MessageList.newInstance(); for (UnixTime m: msgs.<UnixTime>cast()) { ByteBuf encoded = ctx.alloc().buffer(4); encoded.writeInt(m.value()); out.add(encoded); } msgs.releaseAllAndRecycle(); ctx.write(out, promise); // (1) } }1. 注意这里我们传进去一个原始参数ChannelPromise, 当数据真正写入后Netty用他来标记成功还是失败.
public class TimeEncoder extends MessageToByteEncoder<UnixTime> { @Override protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) { out.writeInt(msg.value()); } }
最后留下的任务是在服务端插入TimeEncoder到ChannelPipeline.
关闭你的程序
通过shutdownGracefully()方法关闭Netty程序可以像关闭你创建的EventLoopGroup一样简单. 他返回一个Future, 当EventLoopGroup中断完成后通知你并且属于"boss"和"worker"组的所有channel会被关闭.