7,Netty的Channel与ChannelPipeline源码分析以及Doc介绍

首先我们看看源码分析过程

bind方法
如果有什么不懂可以看看前面的几篇文章,我们发现它其实生成了一个Channel类型的ChannelFuture那么这个类是干什么的呢?我们看看DOc

/**
 * A nexus to a network socket or a component which is capable of I/O
 * operations such as read, write, connect, and bind.
 * (channel  可以认为是一个连接点 , 网络套接制的一个组件,channel对于网络Socket的一个连接组件, 是可以进行IO操作的,读,写,绑定)
 * <p>
 * A channel provides a user:
 * <ul>
 * <li>the current state of the channel (e.g. is it open? is it connected?),</li>
 * (获取到当前的状态,比如说 是不是打开,是否链接上)
 * <li>the {@linkplain ChannelConfig configuration parameters} of the channel (e.g. receive buffer size),</li>
 * (通过以一些配置参数来实现的,提供了一些配置参数,比如说Buffer的大小)
 * <li>the I/O operations that the channel supports (e.g. read, write, connect, and bind), and</li>
 * (提供对当前连接的IO操作,比如说,读,写, 连接,绑定)
 * <li>the {@link ChannelPipeline} which handles all I/O events and requests
 *     associated with the channel.</li>
 *(Channel可以向用户提供ChannelPipeline(channel的管道),是可以处理与当前channel事件所关联的操作与请求所有IO操作 与请求)
 * 也就是说我们这个Channel连接上之后,所有的Channel连接的请求,都可以通过这个ChannelPipeline组件获取到  ChannelPipeline 是将所有的Event_handle() 来有机的组合起来,使得组合之后生成一个链条
 *
 * 问题 ChannelPipeline是在什么时期创建的呢?
 * </ul>
 *
 * <h3>All I/O operations are asynchronous.</h3>
 * <p>所有的IO操作都是异步的
 * All I/O operations in Netty are asynchronous.  It means any I/O calls will
 * return immediately with no guarantee that the requested I/O operation has
 * been completed at the end of the call.
 * 这意味着任何I / O调用将立即返回,并且不保证在调用结束时已完成所请求的I / O操作。
 * Instead, you will be returned with
 * a {@link ChannelFuture} instance which will notify you when the requested I/O
 * operation has succeeded, failed, or canceled.
 * 将返回一个ChannelFuture 来告诉你是否成功了,失败了,或者其他
 * <h3>Channels are hierarchical(可继承的)</h3>
 * <p>
 * A {@link Channel} can have a {@linkplain #parent() parent} depending on
 * how it was created.  For instance, a {@link SocketChannel}, that was accepted
 * by {@link ServerSocketChannel}, will return the {@link ServerSocketChannel}
 * as its parent on {@link #parent()}.
 * <p>
 * 一个Channel可以拥有一个parent(),这取决于这个Channel的创建方式,比如说:一个SocketChannel是由ServerSocketChannel()创建的
 *
 * The semantics of the hierarchical structure depends on the transport
 * implementation where the {@link Channel} belongs to.
 * 层次化的语意取决于Channel的实现,
 * For example, you could
 * write a new {@link Channel} implementation that creates the sub-channels that
 * share one socket connection, as <a href="http://beepcore.org/">BEEP</a> and
 * <a href="http://en.wikipedia.org/wiki/Secure_Shell">SSH</a> do.
 *大概意思就是说你可以编写一个新的Channel并且实现其接口,这个字Channel就可以共享它的连接,与数据等数据 如同SHH 协议一样
 * <h3>Downcast to access transport-specific operations</h3>
 * <p>
 * Some transports exposes additional operations that is specific to the
 * transport.  Down-cast the {@link Channel} to sub-type to invoke such
 * operations.  For example, with the old I/O datagram transport, multicast
 * join / leave operations are provided by {@link DatagramChannel}.
 *同样的因为层次化的结构,也可以进行向下转化,可以访问实现类的一些方法
 * <h3>Release resources</h3>
 * <p>
 * It is important to call {@link #close()} or {@link #close(ChannelPromise)} to release all
 * resources once you are done with the {@link Channel}. This ensures all resources are
 * released in a proper way, i.e. filehandles.
 1 是一个连接点2所有的请求都是异步的
 */

这是Channel里面相关的文档,以及本人理解的一些翻译,然后里面是一些相关的方法.那么它里面的ChannelPipeline看似是一个非常重要的方法.作用我在Doc里面做了理解是

问题1ChannelPipeline是在什么时期创建的呢?用到什么样的模式? 起了什么样的作用 ?

上面的gif 表示的是 bind 方法的源码追踪 我们看看重点关注一下 init() 这个方法,也就是它的初始化方法 init()方法源码追踪
我们到 下面这段代码的用法以及注释 我们看到其实这个channel是直接使用它的 并且下面的方法也是直接想其添加 相关的Channel 也就是说在使用它的时候已经创建好了

		//获取到pipeline
        // 我们看后文看到p 直接被使用 那么到底是什么时候创建的呢 ?  是不是在创建Channel的时候 pipeline是不是已经创建好了呢 ?
        // 生成父类的时候会对Channel对象进行初始化
        //创建好并返回
        ChannelPipeline p = channel.pipeline();

好我们在往下跟看看有没有什么发现 :
在这里插入图片描述
我们追到了DefaultChannelPipeline里面同时 我们在AbstractChannel 这个类的构造方法里面发现它的赋值过程

 	protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline(); //直接通过构造函数赋值的这个pipeline值的
    }

同时看一下他的构造方法:

 protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise = new VoidChannelPromise(channel, true);
        //尾巴 tail上下文的信息 ,并且是链表的操作
        tail = new TailContext(this);
        //一个头
        head = new HeadContext(this);
        //通过链表的方式结合起来 保证顺序
        head.next = tail;
        tail.prev = head;
    }

关于更详细的内容我们可以参考这里做更深的理解
我们来看看它的具体ChannelPipeline里面具体的参数以及说明(用我蹩脚的英文,以及其他参考资料的理解)直接上Doc

**
 * A list of {@link ChannelHandler}s which handles or intercepts inbound events and outbound operations of a
 * {@link Channel}.  {@link ChannelPipeline} implements an advanced form of the
 * <a href="http://www.oracle.com/technetwork/java/interceptingfilter-142169.html">Intercepting Filter</a> pattern
 * to give a user full control over how an event is handled and how the {@link ChannelHandler}s in a pipeline
 * interact with each other.
 * 1是一个ChannelHandler 的列表,2本来就是一个handles 的集合会处理或者拦截进和出的操作,
 * 3实现了拦截过滤器的模式 给用户完全的控制,如何处理一个事件以及管道当中的handle是如何的交互的方式
 * 可以控制Channel
 *
 * <h3>Creation of a pipeline</h3>
 *
 * Each channel has its own pipeline and it is created automatically when a new channel is created.
 * 每一个channel都有自己一个的pipeline 对象 ,在创建channel同时 创建该对象的
 *
 * <h3>How an event flows in a pipeline</h3>
 * 事件是如何在pipeline 当中流动的 ?
 * The following diagram describes how I/O events are processed by {@link ChannelHandler}s in a {@link ChannelPipeline}
 * 下面是描述 IO事件是如何ChannelPipeline当中若干个ChannelHandler 处理的?
 * typically. An I/O event is handled by either a {@link ChannelInboundHandler} or a {@link ChannelOutboundHandler}
 * 所有的IO事件,要么是被ChannelInboundHandler 处理或者 ChannelOutboundHandler 处理的
 * and be forwarded to its closest handler by calling the event propagation methods defined in
 * {@link ChannelHandlerContext}, such as {@link ChannelHandlerContext#fireChannelRead(Object)} and
 * {@link ChannelHandlerContext#write(Object)}.
 * 转发给与之最近的Handler 处理 ,是调用 ChannelHandlerContext 事件传播方法处理的
 *
 * <pre>
 *                                                 I/O Request
 *                                            via {@link Channel} or
 *                                        {@link ChannelHandlerContext}
 *                                                      |
 *  +---------------------------------------------------+---------------+
 *  |                           ChannelPipeline         |               |
 *  |       入栈                                  出栈 \|/              |
 *  |    +---------------------+            +-----------+----------+    |
 *  |    | Inbound Handler  N  |            | Outbound Handler  1  |    |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |              /|\                                  |               |
 *  |               |                                  \|/              |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |    | Inbound Handler N-1 |            | Outbound Handler  2  |    |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |              /|\                                  .               |
 *  |               .                                   .               |
 *  | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
 *  |        [ method call]                       [method call]         |
 *  |               .                                   .               |
 *  |               .                                  \|/              |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |    | Inbound Handler  2  |            | Outbound Handler M-1 |    |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |              /|\                                  |               |
 *  |               |                                  \|/              |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |    | Inbound Handler  1  |            | Outbound Handler  M  |    |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |              /|\                                  |               |
 *  +---------------+-----------------------------------+---------------+
 *                  |                                  \|/
 *  +---------------+-----------------------------------+---------------+
 *  |               |                                   |               |
 *  |       [ Socket.read() ]                    [ Socket.write() ]     |
 *  |   Netty内部实现同时调用了一个Read()           物理层写到外边        |
 *   内部的Io线程
 *  |  Netty Internal I/O Threads (Transport Implementation)            |
 *  +-------------------------------------------------------------------+
 *  </pre>
 * An inbound event is handled by the inbound handlers in the bottom-up direction as shown on the left side of the
 * diagram.  An inbound handler usually handles the inbound data generated by the I/O thread on the bottom of the
 * diagram.  The inbound data is often read from a remote peer via the actual input operation such as
 * {@link SocketChannel#read(ByteBuffer)}.  If an inbound event goes beyond the top inbound handler, it is discarded
 * silently, or logged if it needs your attention.
 * 自下向上处理的入栈处理器通常会处理Io线程生成的数据,通过实际的操作
 * <p>
 * An outbound event is handled by the outbound handler in the top-down direction as shown on the right side of the
 * 自上向下处理的
 * diagram.  An outbound handler usually generates or transforms the outbound traffic such as write requests.
 * If an outbound event goes beyond the bottom outbound handler, it is handled by an I/O thread associated with the
 * {@link Channel}. The I/O thread often performs the actual output operation such as
 * {@link SocketChannel#write(ByteBuffer)}.
 * <p>
 * For example, let us assume that we created the following pipeline:
 * 例如:我们创建了如下
 * <pre>
 * {@link ChannelPipeline} p = ...;
 * p.addLast("1", new InboundHandlerA());
 * p.addLast("2", new InboundHandlerB());
 * p.addLast("3", new OutboundHandlerA());
 * p.addLast("4", new OutboundHandlerB());
 * p.addLast("5", new InboundOutboundHandlerX());
 * </pre>
 * In the example above, the class whose name starts with {@code Inbound} means it is an inbound handler.//表示入栈处理
 * The class whose name starts with {@code Outbound} means it is a outbound handler.//标书出栈处理
 * <p>
 * In the given example configuration, the handler evaluation order is 1, 2, 3, 4, 5 when an event goes inbound.
 * 进入程序的时候入栈处理为1, 2, 3, 4, 5
 * When an event goes outbound, the order is 5, 4, 3, 2, 1.  On top of this principle, {@link ChannelPipeline} skips
 * the evaluation of certain handlers to shorten the stack depth:
 * <ul>
 * <li>3 and 4 don't implement {@link ChannelInboundHandler}, and therefore the actual evaluation order of an inbound
 *     event will be: 1, 2, and 5.</li>
 * <li>1 and 2 don't implement {@link ChannelOutboundHandler}, and therefore the actual evaluation order of a
 *     outbound event will be: 5, 4, and 3.</li>
 * <li>If 5 implements both {@link ChannelInboundHandler} and {@link ChannelOutboundHandler}, the evaluation order of
 *     an inbound and a outbound event could be 125 and 543 respectively.</li>
 * </ul>
 * 34没有实现In接口所以出栈顺序为1,2,5
 *也就是 拦截器处理的方式
 * <h3>Forwarding an event to the next handler</h3>
 *如何将事件转发给下一个处理器?
 * As you might noticed in the diagram shows, a handler has to invoke the event propagation methods in
 * {@link ChannelHandlerContext} to forward an event to its next handler.  Those methods include:
 * <ul>
 * <li>Inbound event propagation methods:
 * 入栈事件传播方法
 *     <ul>
 *     <li>{@link ChannelHandlerContext#fireChannelRegistered()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelActive()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelRead(Object)}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelReadComplete()}</li>
 *     <li>{@link ChannelHandlerContext#fireExceptionCaught(Throwable)}</li>
 *     <li>{@link ChannelHandlerContext#fireUserEventTriggered(Object)}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelWritabilityChanged()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelInactive()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelUnregistered()}</li>
 *     </ul>
 * </li>
 * <li>Outbound event propagation methods:
 * 出栈事件的传播方法
 *     <ul>
 *     <li>{@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#write(Object, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#flush()}</li>
 *     <li>{@link ChannelHandlerContext#read()}</li>
 *     <li>{@link ChannelHandlerContext#disconnect(ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#close(ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#deregister(ChannelPromise)}</li>
 *     </ul>
 * </li>
 * </ul>
 *
 * and the following example shows how the event propagation is usually done:
 *通常是这个事件程序的:
 * <pre>
 * public class MyInboundHandler extends {@link ChannelInboundHandlerAdapter} {
 *    //MyInboundHandler 继承ChannelInboundHandlerAdapter
 *    {@code @Override}
 *     public void channelActive({@link ChannelHandlerContext} ctx) {
 *         System.out.println("Connected!");
 *         //执行
 *         ctx.fireChannelActive();
 *     }
 * }
 *
 * public class MyOutboundHandler extends {@link ChannelOutboundHandlerAdapter} {
 *     {@code @Override}
 *     public void close({@link ChannelHandlerContext} ctx, {@link ChannelPromise} promise) {
 *         System.out.println("Closing ..");
 *         //关闭
 *         ctx.close(promise);
 *     }
 * }
 * </pre>
 *
 * <h3>Building a pipeline</h3>
 * <p>
 * A user is supposed to have one or more {@link ChannelHandler}s in a pipeline to receive I/O events (e.g. read) and
 * to request I/O operations (e.g. write and close).  For example, a typical server will have the following handlers
 * in each channel's pipeline, but your mileage may vary depending on the complexity and characteristics of the
 * protocol and business logic:
 *
 * <ol>
 * <li>Protocol Decoder - translates binary data (e.g. {@link ByteBuf}) into a Java object.</li>
 * <li>Protocol Encoder - translates a Java object into binary data.</li>
 * <li>Business Logic Handler - performs the actual business logic (e.g. database access).</li>
 * </ol>
 *
 * and it could be represented as shown in the following example:
 *
 * <pre>
 * static final {@link EventExecutorGroup} group = new {@link DefaultEventExecutorGroup}(16);
 * ...
 *
 * {@link ChannelPipeline} pipeline = ch.pipeline();
 *添加对象
 * pipeline.addLast("decoder", new MyProtocolDecoder());
 * pipeline.addLast("encoder", new MyProtocolEncoder());
 *
 * // Tell the pipeline to run MyBusinessLogicHandler's event handler methods
 * 告诉这个管道去运行MyBusinessLogicHandler 的事件处理器
 * // in a different thread than an I/O thread so that the I/O thread is not blocked by
 * // a time-consuming task.
 * 告诉它不要阻塞它的方法
 * // If your business logic is fully asynchronous or finished very quickly, you don't
 * // need to specify a group.
 * 这里注意的是,MyBusinessLogicHandler()方法是由group来执行的
 * pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
 * </pre>
 *1 采用addLast()放入一个group  让其MyBusinessLogicHandler 的回调方法在group里面去执行
 * 这个线程跟Io线程不是同一个线程,不会阻塞它的方法
 * 2 应该在自己处理器里面去创建线程池并且去执行相关方法
 * <h3>Thread safety</h3>
 * <p>
 * A {@link ChannelHandler} can be added or removed at any time because a {@link ChannelPipeline} is thread safe.
 * 可以被添加和删除
 * For example, you can insert an encryption handler when sensitive information is about to be exchanged, and remove it
 * after the exchange.
 * 可以插入一个加密的方法在需要的时候同时也可以把他删除掉
 *
 * 总结: Channel和ChannelPipeline 关系,一个事件从产生到被处理其实是被ChannelPipeline 中一个又一个的完成之后转交给下一个去处理
 */

跟一般拦截器请求处理不同的是,如果出栈的时候不需要经过每一个拦截器,而是看他实现某一个接口,而根据接口类型决定出栈顺序
在这里插入图片描述
相关连接
https://www.jianshu.com/p/c551233d5bd8

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值