添加ChannelHandlerContext
// 实例代码 ,首先通过addLast()方法进行添加
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, true)
.childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")
.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());
}
});
跟进addLast方法
// DefaultChannelPipeline.java
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
// 判断channelhandler是否被重复添加
checkMultiplicity(handler);
// 创建channelhandlerContext
newCtx = newContext(group, filterName(name, handler), handler);
addLast0(newCtx);
// If the registered is false it means that the channel was not registered on an eventloop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
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;
}@Override
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 the registered is false it means that the channel was not registered on an eventloop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
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:首先判断channelhandler是否被重复添加
private static void checkMultiplicity(ChannelHandler handler) {
// 判断handler是否继承ChannelHandlerAdapter
if (handler instanceof ChannelHandlerAdapter) {
ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
// 如果非共享,且adder被置为ture,则代表已经添加过,且不能重复添加
if (!h.isSharable() && h.added) {
throw new ChannelPipelineException(
h.getClass().getName() +
" is not a @Sharable handler, so can't be added or removed multiple times.");
}
h.added = true;
}
}
2:创建channelHandlerContext节点,即对channelhandler进行封装,pipeline中节点的数据结构都是channelHandlerContext。
DefaultChannelPipeline.java
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
3:以普通双向链表添加的方式将channelHandlerContext添加到pipeline中
DefaultChannelPipeline.java
addLast0(newCtx);
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
4:回调添加完成事件
DefaultChannelPipeline.java
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));
}
}
}
// 首先获取到当前channelhandlercontext的handler,然后执行handler.handlerAdded(ctx)
ctx.handler().handlerAdded(ctx);
// 注意这里的handlerAdded方法最终会调用到ChannelInitializer的handlerAdded
```java
ChannelInitializer.java
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
// 这里的initChannel(ctx),最终会调用到我们之前在服务端重写的init方法,执行里面的逻辑,检测是否还有
// 别的handler没有添加
initChannel(ctx);
}
}
// 跟进initChannel ChinnelInitializer.java
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) { // Guard against re-entrance.
try {
initChannel((C) ctx.channel());
}
}
```java
// AbstractChannel.java
// 注意在创建pipeline的时候会把当前channel传进去,所以调用ctx.channel()-->pipeline.channel()
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
回到之前讲到的地方,执行完handlerAdded()方法之后,会执行 ctx.setAddComplete(),我们跟进去看一看,
// 通过cas自旋的方式将自己状态设置为ADD_COMPLETE
final void setAddComplete() {
for (;;) {
int oldState = handlerState;
// Ensure we never update when the handlerState is REMOVE_COMPLETE already.
// oldState is usually ADD_PENDING but can also be REMOVE_COMPLETE when an EventExecutor is used that is not
// exposing ordering guarantees.
if (oldState == REMOVE_COMPLETE || HANDLER_STATE_UPDATER.compareAndSet(this, oldState, ADD_COMPLETE)) {
return;
}
}
}
删除channelHandler
接下来,大家看这个handler中的逻辑
public class AuthHandler extends SimpleChannelInboundHandler<ByteBuf> {
// 重写的channnelRead会调用channelRead0方法,最终会在channelread中释放消息,以避免内存泄漏
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf password) throws Exception {
if (paas(password)) {
重点关注下这个remove方法,接下来我们跟进去看看
ctx.pipeline().remove(this);
} else {
ctx.close();
}
}
private boolean paas(ByteBuf password) {
return false;
}
}
DefaultChannelPipeline.java
@Override
public final ChannelPipeline remove(ChannelHandler handler) {
remove(getContextOrDie(handler));
return this;
}
getContextOrDie(handler):根据handler找到封装的channelhandlercontext,我们跟进去看看
private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
if (ctx == null) {
throw new NoSuchElementException(handler.getClass().getName());
} else {
return ctx;
}
}
ok,到了现在重点关注就是这个context方法,这个方法就是我们找到AbstractChannelHandlerContext的关键,我们跟进去看看。
@Override
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;
}
}
ok,到了这里很明显的可以看到是从头结点开始遍历,然后通过比较handler,然后就可以找到context了
接下来我们在进入remove方法中一窥究竟:
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
// 头结点和尾结点不可删除
assert ctx != head && ctx != tail;
// 加锁进行删除
synchronized (this) {
remove0(ctx);
// If the registered is false it means that the channel was not registered on an eventloop yet.
// In this case we remove the context from the pipeline and add a task that will call
// ChannelHandler.handlerRemoved(...) once the channel is registered.
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;
}
进入remove0():观察是发现标准的链表删除
private static void remove0(AbstractChannelHandlerContext ctx) {
AbstractChannelHandlerContext prev = ctx.prev;
AbstractChannelHandlerContext next = ctx.next;
prev.next = next;
next.prev = prev;
}
删除之后,进入删除回调事件:
callHandlerRemoved0(ctx):
private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
// Notify the complete removal.
try {
try {
//进入用户代码执行handlerRemoved逻辑
ctx.handler().handlerRemoved(ctx);
} finally {
// 设置handlerstate为REMOVE_COMPLETE;
ctx.setRemoved();
}
} catch (Throwable t) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
}
}
综上删除handler的逻辑:
1:找到handlercontext
2:执行删除逻辑
3:进入用户回调函数
inbound事件的传播
定义一个InBoundHandler:
public class InBoundHandlerB extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("InBoundHandlerB: " + msg);
ctx.fireChannelRead(msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.channel().pipeline().fireChannelRead("hello world");
}
}
在这里,我先提一下,ctx.channel().pipeline().firechannelRead()与直接使用ctx.fireChannelRead()的区别,第一个是从head节点向下传播inbound事件,而第二种是从当前节点向下传播事件。
跟进fireChannelRead()方法:
DefaultChannelPipeline.java
@Override
public final ChannelPipeline fireChannelRead(Object msg) {
AbstractChannelHandlerContext.invokeChannelRead(head, msg);
return this;
}
进入到AbstractChannelHandlerContext.java:
// 这里的next在第一个调用时就是HeadContext
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRead(m);
}
});
}
}
跟进head的invokeChannelRead方法:
private void invokeChannelRead(Object msg) {
if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRead(msg);
}
}
跟进fireChannelRead(msg):这里不做什么事情,通过findContextInbound()找到下一个context,然后通过 invokeChannelRead将事件向下传播
@Override
public ChannelHandlerContext fireChannelRead(final Object msg) {
invokeChannelRead(findContextInbound(), msg);
return this;
}
进入findContextInbound方法:
// 找到下一个inbound handlercontext
private AbstractChannelHandlerContext findContextInbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
return ctx;
}
跟进invokeChannelRead():
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRead(m);
}
});
}
}
继续跟进去 next.invokeChannelRead(m);
private void invokeChannelRead(Object msg) {
if (invokeHandler()) {
try {
// 在这个channelread方法中会调用到我们添加的handler的channelread方法,之后在我们的handler中可以定义向下传播逻辑,这样的话会再走一遍上面的流畅
/*
1:invokeChannelRead(findContextInbound(), msg);
2:invokeChannelRead(final AbstractChannelHandlerContext next, Object msg)
next.invokeChannelRead(m);
invokeChannelRead(Object msg)
*/
((ChannelInboundHandler) handler()).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRead(msg);
}
}