在本文中我们将讲解pipeline的创建执行等,pipeline在很多地方都有这种概念,像是tomcat中,Spring的AOP中,都是通过链式调用一个一个的对传入的对象进行处理。
pipeline = newChannelPipeline();
我们将从这行代码开始进行我们的源码之旅。
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
直接创建了一个默认的pipeline,并且传入了当前的channel对象
protected DefaultChannelPipeline(Channel channel) {
//保存channel对象
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
//创建一个尾节点
tail = new TailContext(this);
//创建一个头节点
head = new HeadContext(this);
//形成一个双向链表
head.next = tail;
tail.prev = head;
}
从这个构造方法中我们就可以看出,实际上,pipeline对传入的信息进行处理是通过里面保存的节点,这些节点有组成了一个双向链表进行链式调用。先来看一些尾节点是如何创建的:
tail = new TailContext(this);
尾节点是直接通过构造方法创建的并且传入当前的pipeline对象:
发现这个尾节点实现了ChannelInboundHandler接口,应该是处理入方向的事件,我们来看一下这个接口中有什么方法:
/**
* The {@link Channel} of the {@link ChannelHandlerContext} was registered with its {@link EventLoop}
*/
void channelRegistered(ChannelHandlerContext ctx) throws Exception;
/**
* The {@link Channel} of the {@link ChannelHandlerContext} was unregistered from its {@link EventLoop}
*/
void channelUnregistered(ChannelHandlerContext ctx) throws Exception;
/**
* The {@link Channel} of the {@link ChannelHandlerContext} is now active
*/
void channelActive(ChannelHandlerContext ctx) throws Exception;
/**
* The {@link Channel} of the {@link ChannelHandlerContext} was registered is now inactive and reached its
* end of lifetime.
*/
void channelInactive(ChannelHandlerContext ctx) throws Exception;
/**
* Invoked when the current {@link Channel} has read a message from the peer.
*/
void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
/**
* Invoked when the last message read by the current read operation has been consumed by
* {@link #channelRead(ChannelHandlerContext, Object)}. If {@link ChannelOption#AUTO_READ} is off, no further
* attempt to read an inbound data from the current {@link Channel} will be made until
* {@link ChannelHandlerContext#read()} is called.
*/
void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
/**
* Gets called if an user event was triggered.
*/
void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
/**
* Gets called once the writable state of a {@link Channel} changed. You can check the state with
* {@link Channel#isWritable()}.
*/
void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;
/**
* Gets called if a {@link Throwable} was thrown.
*/
@Override
@SuppressWarnings("deprecation")
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
都是些读事件,注册事件,激活事件的处理。下面我们看一下它的构造方法:
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
boolean inbound, boolean outbound) {
this.name = ObjectUtil.checkNotNull(name, "name");
this.pipeline = pipeline;
this.executor = executor;
this.inbound = inbound;
this.outbound = outbound;
// Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
ordered = executor == null || executor instanceof OrderedEventExecutor;
}
保存了我们传入的参数,尤其要注意,pipeline是通过当前节点inbound和outbound 是true还是false选择合适的节点的。
需要注意的是头节点是同时继承了ChannelInboundHandler和ChannelOutboundHandler接口,但是记录的自己是一个出站节点。
接下来我们看一下pipeline是如何添加一个节点的
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
将我们传入的handler数组当作参数去调用另外一个方法:
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
//进行非空判断
if (handlers == null) {
throw new NullPointerException("handlers");
}
//通过循环一个一个的将这些handler添加到链表的尾部
for (ChannelHandler h: handlers) {
if (h == null) {
break;
}
addLast(executor, null, h);
}
return this;
}
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
//封装成一个新的节点
newCtx = newContext(group, filterName(name, handler), handler);
//最终封装好的新节点添加到链表上
addLast0(newCtx);
// 如果添加失败了,那么就会把这个节点的封装成一个任务放到队列里面稍后执行
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
//添加完成之后调用回调方法
callHandlerAdded0(newCtx);
return this;
}
在这个方法中做了两件事:
1、将handler封装成一个context节点并最终调用添加方法
2、添加完成之后调用回调方法
接下来我们一个一个的去看这是怎么实现的:
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
这就是双向链表添加一个新节点的操作,没什么好说的
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
//添加完成后的回调方法
ctx.handler().handlerAdded(ctx);
ctx.setAddComplete();
} catch (Throwable t) {
boolean removed = false;
try {
remove0(ctx);
try {
ctx.handler().handlerRemoved(ctx);
} finally {
ctx.setRemoved();
}
removed = true;
} catch (Throwable t2) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to remove a handler: " + ctx.name(), t2);
}
}
if (removed) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; removed.", t));
} else {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; also failed to remove.", t));
}
}
}
这个回调方法是非常重要的,ctx.handler().handlerAdded(ctx),这个方法中调用了用户自定义实现的方法,就是下面这几行代码:
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new OutBoundHandlerA());
ch.pipeline().addLast(new OutBoundHandlerC());
ch.pipeline().addLast(new OutBoundHandlerB());
}
});
这是用户通过添加一个childHandler而在里面的自定义方法中添加多个handler,而这几个handler的添加就是通过上面的回调函数放上去的,添加完成之后就会将这个childHandler删除掉。
下面我们就来看一下pipeline是如何删除一个节点的:
public final ChannelHandlerContext context(ChannelHandler handler) {
if (handler == null) {
throw new NullPointerException("handler");
}
AbstractChannelHandlerContext ctx = head.next;
for (;;) {
if (ctx == null) {
return null;
}
if (ctx.handler() == handler) {
return ctx;
}
ctx = ctx.next;
}
}
首先需要在链表上查找指定的handler对应的ctx,找到之后返回ctx,没有就返回空:
private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
if (ctx == null) {
throw new NoSuchElementException(handler.getClass().getName());
} else {
return ctx;
}
}
接着会判断是否存在handler,如果存在那么直接返回,不存在抛出异常
public final ChannelPipeline remove(ChannelHandler handler) {
remove(getContextOrDie(handler));
return this;
}
然后就会继续调用remove方法,参数则是handler对应的context
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
assert ctx != head && ctx != tail;
synchronized (this) {
remove0(ctx);
if (!registered) {
callHandlerCallbackLater(ctx, false);
return ctx;
}
EventExecutor executor = ctx.executor();
if (!executor.inEventLoop()) {
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerRemoved0(ctx);
}
});
return ctx;
}
}
callHandlerRemoved0(ctx);
return ctx;
}
这段代码就和add方法是一样的了,先调用最终的remove方法,通过链表的操作删除节点,然后调用回调方法,我们就不进去看了。