Netty之ChannelPipeline(一)添加ChannelHandler

在Netty中每个Channel都有且仅有一个ChannelPipeline与之对应,而每个ChannelPipeline中又维护了一个由ChannelHandlerContext组成的双向链表,链表头是HeadContext,链表尾是TailContext,并且每个ChannelHandlerContext中又关联着一个ChannelHandler,如图示:在这里插入图片描述
每个Channel都会有一个相应的ChannelPipeline:

    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        unsafe = newUnsafe();
        pipeline = new DefaultChannelPipeline(this);
    }

这里代码是AbstractChannel构造器,在构造器中会初始化他为DefaultChannelPipeline的实例,这里的代码就印证了每个Channel都会有一个相应的ChannelPipeline的观点。

io.netty.channel.DefaultChannelPipeline,DefaultChannelPipeline是ChannelPipeline的实现类。
接下来看DefaultChannelPipeline的初始化过程:

public DefaultChannelPipeline(AbstractChannel channel) {
    if (channel == null) {
        throw new NullPointerException("channel");
    }
    this.channel = channel;

    tail = new TailContext(this);
    head = new HeadContext(this);

    head.next = tail;
    tail.prev = head;
}

这里首先将与其关联的Channel保存到字段channel中,接着实例化两个ChannelHandlerContext,HeadContext与TailContext构成双向链表,这里HeadContext和TailContext继承于AbstractChannelHandlerContext的同时也实现了ChannelHandler接口,所以他们有Context和Handler的双重属性。

在pipeline内添加节点是在是在这两点中间添加context,链表头尾依旧是这两个。

ChannelPipeline上相关方法,addFirst、addBefore、addAfter、addLast都是将一个ChannelHandler添加到ChannelPipeline中。

这里只看addLast方法的具体实现:
addLast(EventExecutorGroup group, String name, ChannelHandler handler) 方法,添加一个 ChannelHandler 对象到 pipeline 中:

@Override
@SuppressWarnings("Duplicates")
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
      final AbstractChannelHandlerContext newCtx;
      synchronized (this) { // 同步,为了防止多线程并发操作 pipeline 底层的双向链表
          // 检查是否有重复 handler
          checkMultiplicity(handler);
  
          // 创建节点名 调用filterName()方法获取ChannelHandler名字
          // 创建节点 调用newContext()方法创建DefaultChannelHandlerContext节点
         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) {
             // 设置 AbstractChannelHandlerContext 准备添加中
             newCtx.setAddPending();
             // 添加 PendingHandlerCallback 回调
             callHandlerCallbackLater(newCtx, true);
             return this;
         }
 
         // 不在 EventLoop 的线程中,提交 EventLoop 中,执行回调用户方法
         EventExecutor executor = newCtx.executor();
        if (!executor.inEventLoop()) {
             // 设置 AbstractChannelHandlerContext 准备添加中,即就是设置状态为准备添加
             newCtx.setAddPending();
            // 提交 EventLoop 中,执行回调 ChannelHandler added 事件
             executor.execute(new Runnable() {
                 @Override
                 public void run() {
                     callHandlerAdded0(newCtx);
                 }
             });
             return this;
         }
     }
 
     // 回调 ChannelHandler added 事件
     callHandlerAdded0(newCtx);
     return this;
 }
  1. filterName
private String filterName(String name, ChannelHandler handler) {
    if (name == null) { 
    //如果没有传入默认的名字,则调用generateName方法,根据ChannelHandler生成一个唯一的名字。
        return generateName(handler);
    }
    //如果已经传入默认的名字则调用checkDuplicateName()方法检验名字唯一性
    checkDuplicateName(name); // <2>
    return name;
}
  • generateName()方法生成唯一的名字:
private String generateName(ChannelHandler handler) {
      // 从缓存中查询,是否已经生成默认名字
      Map<Class<?>, String> cache = nameCaches.get();
      Class<?> handlerType = handler.getClass();
      String name = cache.get(handlerType);
      // 若未生成过,进行生成
      if (name == null) {
          name = generateName0(handlerType);
          cache.put(handlerType, name);
     }
 
     // 判断是否存在相同名字的节点
     // It's not very likely for a user to put more than one handler of the same type, but make sure to avoid
     // any name conflicts.  Note that we don't cache the names generated here.
     if (context0(name) != null) {
         // 若存在,则使用基础名字 + 编号,循环生成,直到一个是唯一的
         String baseName = name.substring(0, name.length() - 1); // Strip the trailing '0'.
         for (int i = 1;; i ++) {
             String newName = baseName + i;
             if (context0(newName) == null) { // // 判断是否存在相同名字的节点
                 name = newName;
                 break;
             }
         }
     }
     return name;
 }
private AbstractChannelHandlerContext context0(String name) {
    AbstractChannelHandlerContext context = head.next;
    // 顺序向下遍历节点,判断是否有指定名字的节点。如果有,则返回该节点。
    while (context != tail) {
        if (context.name().equals(name)) {
            return context;
        }
        context = context.next;
    }
    return null;
}
  • checkDuplicateName(String name) 方法,校验名字唯一:
private void checkDuplicateName(String name) {
    if (context0(name) != null) {
    // 如果存在节点就说明不唯一,抛异常
        throw new IllegalArgumentException("Duplicate handler name: " + name);
    }
}
  1. newContext(EventExecutorGroup group, String name, ChannelHandler handler) 方法,创建 DefaultChannelHandlerContext 节点。而这个节点,内嵌传入的 ChannelHandler 参数。代码如下
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
    return new DefaultChannelHandlerContext(this, childExecutor(group) , name, handler);
}
  • childExecutor(EventExecutorGroup group) 方法
private EventExecutor childExecutor(EventExecutorGroup group) {
//一般情况下是这个:
    // 不创建子执行器
    if (group == null) {
        return null;
    }
    // 根据配置项 SINGLE_EVENTEXECUTOR_PER_GROUP ,每个 Channel 从 EventExecutorGroup 获得不同 EventExecutor 执行器
    Boolean pinEventExecutor = channel.config().getOption(ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP);
    if (pinEventExecutor != null && !pinEventExecutor) {
        return group.next();
    }
    // 通过 childExecutors 缓存实现,一个 Channel 从 EventExecutorGroup 获得相同 EventExecutor 执行器
    Map<EventExecutorGroup, EventExecutor> childExecutors = this.childExecutors;
    if (childExecutors == null) {
        // Use size of 4 as most people only use one extra EventExecutor.
        childExecutors = this.childExecutors = new IdentityHashMap<EventExecutorGroup, EventExecutor>(4);
    }
    // Pin one of the child executors once and remember it so that the same child executor
    // is used to fire events for the same channel.
    EventExecutor childExecutor = childExecutors.get(group);
    // 缓存不存在,进行 从 EventExecutorGroup 获得 EventExecutor 执行器
    if (childExecutor == null) {
        childExecutor = group.next();
        childExecutors.put(group, childExecutor); // 进行缓存
    }
    return childExecutor;
}
  1. addLast0()方法加入到最后一个:
    实际就是一个双向链表的插入操作
private void addLast0(AbstractChannelHandlerContext newCtx) {
    // 获得 tail 节点的前一个节点
    AbstractChannelHandlerContext prev = tail.prev;
    // 新节点,指向 prev 和 tail 节点
    newCtx.prev = prev; 
    newCtx.next = tail; 
    // 在 prev 和 tail ,指向新节点
    prev.next = newCtx; 
    tail.prev = newCtx; 
}
  1. callHandlerAdded0()方法
    callHandlerAdded0(AbstractChannelHandlerContext) 方法,执行回调 ChannelHandler 添加完成( added )事件
 private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
      try {
          // We must call setAddComplete before calling handlerAdded. Otherwise if the handlerAdded method generates
          // any pipeline events ctx.handler() will miss them because the state will not allow it.
          // 设置 AbstractChannelHandlerContext 已添加
          ctx.setAddComplete();
          // 回调 ChannelHandler 添加完成( added )事件
          //一般来说通过这个方法来初始化ChannelHandler,由于这个方法的在EventLoop的线程中执行,所以要尽量避免执行时间过长。
          ctx.handler().handlerAdded(ctx);
      } catch (Throwable t) {
         // 发生异常,移除该节点
         boolean removed = false;
         try {
             remove0(ctx); // 移除
             try {
                 ctx.handler().handlerRemoved(ctx); 
                 // 回调 ChannelHandler 移除完成( removed )事件
             } 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));
         }
     }
 }

addLast(ChannelHandler… handlers) 添加任意数量的ChannelHandler对象:
调用addLast(executor, null, h); 添加一个ChannelHandler对象到pipeline

@Override
public final ChannelPipeline addLast(ChannelHandler... handlers) {
    return addLast(null, handlers);
}

@Override
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
    if (handlers == null) {
        throw new NullPointerException("handlers");
    }

    for (ChannelHandler h: handlers) {
        if (h == null) {
            break;
        }
        addLast(executor, null, h); 
        //添加一个ChannelHandler对象到pipeline
    }

    return this;
}

添加部分就先看这些。

发布了26 篇原创文章 · 获赞 4 · 访问量 2381

猜你喜欢

转载自blog.csdn.net/weixin_43257196/article/details/104108956