前面分析过ChannelPipeline的定义,以及它的集成体系,这篇文章深入一些,分写一个它的实现类DefaultChannelPipeline,它直接实现了ChannelPipeline接口。。。
我们首先来看它的一些重要的属性:
final Channel channel; //当前pipeline所属的channel
//head和tail都是handler上下文,但是不同的是head它包含的是一个outboundhandler,同时也是operationhanderl
//而tail包含的是一个inboundhandler,同时也是一个stathandler
final DefaultChannelHandlerContext head;
final DefaultChannelHandlerContext tail;
private final Map name2ctx =
new HashMap(4); //用于保存所有的handlercontext与name之间的关系
其实这些属性基本上都能知道是干嘛的,首先channel保存的是当前pipeline所依附的channel,
然后这里的head与tail都是handlercontext,从名字就会知道他们会用来构成一个链,具体的待会从构造函数中就能知道它们用来干嘛了。。。
然后还有一个map用来存储名字与handler之间的关系。。。。
接下来我们来看它的构造函数:
public DefaultChannelPipeline(Channel channel) {
if (channel == null) {
throw new NullPointerException("channel");
}
this.channel = channel; //为所属的channel赋值
TailHandler tailHandler = new TailHandler(); //构造尾handler,它是一个inboundhandler,同时当然也是stathandler了
tail = new DefaultChannelHandlerContext(this, generateName(tailHandler), tailHandler);
HeadHandler headHandler;
//接下来开始构造headhandler,它是一个outboundhandler,也就是一个operationhandler
switch (channel.metadata().bufferType()) {
case BYTE:
//operationhandler需要用channel对象的unsafe对象来构造
headHandler = new ByteHeadHandler(channel.unsafe());
break;
case MESSAGE:
headHandler = new MessageHeadHandler(channel.unsafe());
break;
default:
throw new Error("unknown buffer type: " + channel.metadata().bufferType());
}
head = new DefaultChannelHandlerContext(this, generateName(headHandler), headHandler);
//将他们构成链表
head.next = tail;
tail.prev = head;
}
还是相对比较简单,首先是为channel属性赋值,接着初始化head与tail属性,
这里需要预先预习一下两种handler,inboundhandler与outboundhandler,同时inboundhandler实现了stathandler接口,outboundhandler实现了operationhandler接口,说白了inboundhandler用来处理读进来的数据,而outboundhandler用来具体对外的数据操作。。。
这里head将最终包含一个outboundhandler,而tail将最终包含一个inboundhandler。。。
而且最终handler的调用方式是:
(1)对于已经读取的数据需要处理,将会从head开始向下遍历,找到第一个inboundhandler,然后将数据保存到它的buffer,然后由它来处理。。。
(2)对于需要进行对外的操作,那么将会从tail开始,向上遍历,找到第一个outboundhandler,然后由它来处理。。。
我们首先来看内部类TailHandler的实现:
// A special catch-all handler that handles both bytes and messages.
static final class TailHandler implements ChannelInboundHandler {
final ByteBuf byteSink = Unpooled.buffer(0);
final MessageBuf
它直接继承自inboundhandler,因此实现了所有inboundhandler的方法,其实也就实现了inboundBufferUpdated方法,其余的方法都是空的。。。
这是默认的tail包含的handler,因此也就是最后一个inboundhandler,如果最终不得不由这个handler来处理读取进来的数据,那么就是说明在整个pipeline上面根本就没有用户定义的inboundhandler来处理读进来的数据,这个时候进行的操作就是直接将这些读取的数据抛弃掉就好了。。。。
接下来来看内部类HeadHandler的定义:
abstract static class HeadHandler implements ChannelOutboundHandler {
protected final Unsafe unsafe;
ByteBuf byteSink;
MessageBuf msgSink;
boolean initialized;
//构造函数,这个时候的unsafe就是channel的unsafe对象
protected HeadHandler(Unsafe unsafe) {
this.unsafe = unsafe;
}
void init(ChannelHandlerContext ctx) {
assert !initialized;
switch (ctx.channel().metadata().bufferType()) {
case BYTE:
byteSink = ctx.alloc().ioBuffer();
msgSink = Unpooled.messageBuffer(0);
break;
case MESSAGE:
byteSink = Unpooled.buffer(0);
msgSink = Unpooled.messageBuffer();
break;
default:
throw new Error();
}
}
@Override
public final void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// NOOP
}
@Override
public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
// NOOP
}
@Override
public final void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
throws Exception {
unsafe.bind(localAddress, promise);
}
@Override
public final void connect(
ChannelHandlerContext ctx,
SocketAddress remoteAddress, SocketAddress localAddress,
ChannelPromise promise) throws Exception {
unsafe.connect(remoteAddress, localAddress, promise);
}
@Override
public final void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
unsafe.disconnect(promise);
}
@Override
public final void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
unsafe.close(promise);
}
@Override
public final void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
unsafe.deregister(promise);
}
@Override
public final void read(ChannelHandlerContext ctx) {
unsafe.beginRead();
}
@Override
public final void sendFile(
ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception {
unsafe.sendFile(region, promise);
}
@Override
public final Buf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
throw new Error();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.fireExceptionCaught(cause);
}
}
它是一个抽象类,因为需要分为两种,基于byte类型的以及基于message类型的。。。
另外我们可以看到一个unsafe对象,其实这个就是当前所属的channel的unsafe对象,对于实际的操作,例如connect,bind等,其实都是基于这个对象来实现的。。。。
对于它的子类,ByteHeadHandler和MessageHeadHandler,他们具体实现了flush方法,用于发送数据,其实数白了最后总还是用unsafe的flush方法来实现的...
看到这里,也能看出,对于outboundhandler不一定需要用户自定义也可以,因为默认的head将会按照channel的unsafe对象将他们发送出去,但是inboundhandler就必须自己定义了。。。。
这里我们来具体分析一个方法:fireInboundBufferUpdated,它是在事件循环中,通过channel的unsafe对象读取到数据后,将会调用的方法,表示已经有数据已经读取了,然后触发inboundhandler来处理这些数据,在DefaultChannelPipeline中这个方法的实现很简单:
//当从nio的channel中读取了数据之后会调用这个方法,最终会激活handler链上的第一个inboundhandler的inboundBufferUpdated方法来处理这些数据
public ChannelPipeline fireInboundBufferUpdated() {
head.fireInboundBufferUpdated();
return this;
}
说白了就是调用headhandler的context的fireInboundBufferUpdated方法(headhandler是一个outboundhandler),那么我们接下来来看看DefaultChannelHandlerContext中该方法的定义吧:
@Override
//当已经有数据从nio的channel中读取进来的时候,会调用该方法,用于处理读取进来的数据
public ChannelHandlerContext fireInboundBufferUpdated() {
EventExecutor executor = executor(); //用于获取执行代码的executor,其实一般情况下就是当前channel所属的eventLoop
if (executor.inEventLoop()) { //如果executor就是当前的eventLoop,那么就直接执行好了否则的话需要向executor提交任务
fireInboundBufferUpdated0(findContextInbound());
} else {
Runnable task = fireInboundBufferUpdated0Task;
if (task == null) {
fireInboundBufferUpdated0Task = task = new Runnable() {
@Override
public void run() {
fireInboundBufferUpdated0(findContextInbound());
}
};
}
executor.execute(task);
}
return this;
}
实现首先是判断当前的executor的线程是否就是当前的执行线程,其实一般情况下都是的,也就是当前channel所属的eventLoop,除非为当前的handler指定了额外的executor,如果有额外的executor的话,那么就需要通过task的方法来执行了。。。这里在具体的执行之前先调用了findContextInbound方法来找到第一个inboundhandler的context,我们来看看该方法的定义吧:
}
//headhandler的context会调用该方法,用于向下寻找,找到第一个inboundhandler的context
private DefaultChannelHandlerContext findContextInbound() {
DefaultChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!(ctx.handler() instanceof ChannelStateHandler));
return ctx;
}
这里就能看出,对于读取进来的数据,handler是从head到tail执行的顺序了吧、、、
好了接下来来看fireInboundBufferUpdated0方法:
private void fireInboundBufferUpdated0(final DefaultChannelHandlerContext next) {
//handler的buffer之间的联系
feedNextInBridge();
// This comparison is safe because this method is always executed from the executor.
if (next.executor == executor) { //有可能找到的第一个inboundhandler的executor不是当前这个executor,不过一般还是当前channel注册到的eventLoop
next.invokeInboundBufferUpdated(); //这里说白了就是调用具体的inboundhandler的inboundBufferUpdated方法
} else {
Runnable task = next.invokeInboundBufferUpdatedTask;
if (task == null) {
next.invokeInboundBufferUpdatedTask = task = new Runnable() {
@Override
public void run() {
next.invokeInboundBufferUpdated();
}
};
}
next.executor().execute(task);
}
}
先刷新了bridge,接着还是判断了executor,最后在调用invokeInboundBufferUpdated方法,来看它的定义:
//具体调用inboundhandler的inboundBufferUpdated方法来处理读进来的数据
private void invokeInboundBufferUpdated() {
if (isInboundFreed()) {
return;
}
ChannelStateHandler handler = (ChannelStateHandler) handler();
if (handler instanceof ChannelInboundHandler) {
for (;;) {
try {
boolean flushedAll = flushInboundBridge();
handler.inboundBufferUpdated(this); //调用inboundBufferUpdated函数来处理读进来的数据
if (flushedAll) {
break;
}
} catch (Throwable t) {
notifyHandlerException(t);
break;
} finally {
if (handler instanceof ChannelInboundByteHandler && !isInboundFreed()) {
try {
((ChannelInboundByteHandler) handler).discardInboundReadBytes(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
}
freeHandlerBuffersAfterRemoval();
}
}
} else {
try {
handler.inboundBufferUpdated(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
}
}
这里调用了inboundhandler的inboundBufferUpdated方法,这个用过netty的就应该很清楚了吧。。。
好了,对于真个数据进来的处理流程就差不了。。。好像也不是说的太细,而且有一些细节我也没有搞的太清楚,例如bridge,不过以后补上吧。。。