转载自http://blog.csdn.net/zxhoo/article/details/17264263
netty4
是一个和类似的java nio框架,目前的最新版本是,这两个框架的主要作者好像都是。
channel
channel是netty最核心的接口,一个channel就是一个联络socket的通道,通过channel,你可以对socket进行各种操作。
channelhandler
用netty编写网络程序的时候,你很少直接操纵channel,而是通过channelhandler来间接操纵channel。
netty中的所有handler都实现自channelhandler接口。按照输出输出来分,分为channelinboundhandler、channeloutboundhandler两大类。
channelinboundhandler对从客户端发往服务器的报文进行处理,一般用来执行解码、读取客户端数据、进行业务处理等;
channeloutboundhandler对从服务器发往客户端的报文进行处理,一般用来进行编码、发送报文到客户端。
channelpipeline
channelpipeline实际上应该叫做channelhandlerpipeline,可以把channelpipeline看成是一个chandlerhandler的链表,当需要对channel进行某种处理的时候,pipeline负责依次调用每一个handler进行处理。每个channel都有一个属于自己的pipeline,调用channel#pipeline()方法可以获得channel的pipeline,调用pipeline#channel()方法可以获得pipeline的channel。
channelpipeline的方法有很多,其中一部分是用来管理channelhandler的,如下面这些:
channelpipeline addfirst(string name, channelhandler handler); channelpipeline addlast(string name, channelhandler handler); channelpipeline addbefore(string basename, string name, channelhandler handler); channelpipeline addafter(string basename, string name, channelhandler handler); channelpipeline remove(channelhandler handler); channelhandler remove(string name); channelhandler removefirst(); channelhandler removelast(); channelpipeline replace(channelhandler oldhandler, string newname, channelhandler newhandler); channelhandler replace(string oldname, string newname, channelhandler newhandler); channelhandler first(); channelhandler last(); channelhandler get(string name);
channelhandlercontext
channelpipeline并不是直接管理channelhandler,而是通过channelhandlercontext来间接管理,这一点通过channelpipeline的默认实现defaultchannelpipeline可以看出来。
调用channelhandlercontext#channel()方法可以得到和context绑定的channel,调用channelhandlercontext#handler()方法可以得到和context绑定的handler。
channelpipeline和channelhandlercontext默认实现
defaultchannelhandlercontext和defaultchannelpipeline是channelhandlercontext和channelpipeline的默认实现,下面是它们的部分代码:
final class defaultchannelhandlercontext extends defaultattributemap implements channelhandlercontext { volatile defaultchannelhandlercontext next; volatile defaultchannelhandlercontext prev; private final boolean inbound; private final boolean outbound; private final abstractchannel channel; private final defaultchannelpipeline pipeline; private final string name; private final channelhandler handler; private boolean removed; // ... }
final class defaultchannelpipeline implements channelpipeline { // ... final defaultchannelhandlercontext head; final defaultchannelhandlercontext tail; // ... }
从上面的代码可以看出,在defaultpipeline内部,defaultchannelhandlercontext组成了一个双向链表:
再来看看defaultchannelpipeline的构造函数:
public defaultchannelpipeline(abstractchannel channel) { if (channel == null) { throw new nullpointerexception("channel"); } this.channel = channel; tailhandler tailhandler = new tailhandler(); tail = new defaultchannelhandlercontext(this, null, generatename(tailhandler), tailhandler); headhandler headhandler = new headhandler(channel.unsafe()); head = new defaultchannelhandlercontext(this, null, generatename(headhandler), headhandler); head.next = tail; tail.prev = head; }
可以看到,defaultchinnelpipeline内部使用了两个特殊的handler来表示handler链的头和尾:
channelhandler的种类
netty中的所有handler都实现自channelhandler接口。按照输出输出来分,分为channelinboundhandler、channeloutboundhandler两大类。channelinboundhandler对从客户端发往服务器的报文进行处理,一般用来执行解码、读取客户端数据、进行业务处理等;channeloutboundhandler对从服务器发往客户端的报文进行处理,一般用来进行编码、发送报文到客户端。
从上面defaultchannelhandlercontext代码可以知道,handler实际上分为两种,inbound和outbound,这一点也可以从channelhandler接口的子接口得到证明:
public interface channelinboundhandler extends channelhandler { // ... } public interface channeloutboundhandler extends channelhandler { // ... }
事件的传播
为了搞清楚事件如何在pipeline里传播,让我们从channel的抽象子类abstractchannel开始,下面是abstractchannel#write()方法的实现:
public abstract class abstractchannel extends defaultattributemap implements channel { // ... @override public channel write(object msg) { return pipeline.write(msg); } // ... }
abstractchannel直接调用了pipeline的write()方法:
final class defaultchannelpipeline implements channelpipeline { // ... @override public channelfuture write(object msg) { return tail.write(msg); } // ... }
因为write是个outbound事件,所以defaultchannelpipeline直接找到tail部分的context,调用其write()方法:
接着看defaultchannelhandlercontext的write()方法:
final class defaultchannelhandlercontext extends defaultattributemap implements channelhandlercontext { // ... @override public channelfuture write(object msg) { return write(msg, newpromise()); } @override public channelfuture write(final object msg, final channelpromise promise) { if (msg == null) { throw new nullpointerexception("msg"); } validatepromise(promise, true); write(msg, false, promise); return promise; } private void write(object msg, boolean flush, channelpromise promise) { defaultchannelhandlercontext next = findcontextoutbound(); next.invokewrite(msg, promise); if (flush) { next.invokeflush(); } } private defaultchannelhandlercontext findcontextoutbound() { defaultchannelhandlercontext ctx = this; do { ctx = ctx.prev; } while (!ctx.outbound); return ctx; } private void invokewrite(object msg, channelpromise promise) { try { ((channeloutboundhandler) handler).write(this, msg, promise); } catch (throwable t) { notifyoutboundhandlerexception(t, promise); } } // ... }
context的write()方法沿着context链往前找,直至找到一个outbound类型的context为止,然后调用其invokewrite()方法:
invokewrite()接着调用handler的write()方法:
最后看看channeloutboundhandleradapter的write()方法实现:
public class channeloutboundhandleradapter extends channelhandleradapter implements channeloutboundhandler { // ... @override public void write(channelhandlercontext ctx, object msg, channelpromise promise) throws exception { ctx.write(msg, promise); } // ... }
默认的实现调用了context的write()方法而不做任何处理,这样write事件就沿着outbound链继续传播:
可见,pipeline的事件传播,是靠pipeline,context和handler共同协作完成的。