1. 程式人生 > 其它 >netty原始碼分析一

netty原始碼分析一

一個channel對應一個pipeline,pipeline是channel的成員變數,初始化channel的時候就初始化了pipeline,一個pipeline裡面包含多個handler,其中在初始化handler的時候,會同時初始化head/tail兩個handlerContext;一個DefaultChannelHandlerContext裡面包含一個handler,換句話說handler是以handlerContext的形式存在。

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractChannel.class);

    private final Channel parent;  // 代表父類channel
    private final ChannelId id;    // 採用預設方式生成的全域性唯一id
    //實現具體的連線與讀/寫資料,如網路的讀/寫、鏈路關閉、發起連線等
    private final Unsafe unsafe;   // Unsafe例項
    //一個Handler的容器,也可以將其理解為一個Handler鏈。Handler主要處理資料的編/解碼和業務邏輯。
    private final DefaultChannelPipeline pipeline; // 當前channel對應的DefaultChannelPipeline
    private final VoidChannelPromise unsafeVoidPromise = new VoidChannelPromise(this, false);
    private final CloseFuture closeFuture = new CloseFuture(this);

    private volatile SocketAddress localAddress;
    private volatile SocketAddress remoteAddress;
    private volatile EventLoop eventLoop;  // 當前channel註冊的EventLoop 每個Channel對應一條EventLoop執行緒。
    private volatile boolean registered;
    private boolean closeInitiated;
    private Throwable initialCloseCause;

    /**
     * Cache for the string representation of this channel
     */
    private boolean strValActive;
    private String strVal;

    /**
     * Creates a new instance.
     *
     * @param parent the parent of this channel. {@code null} if there's no parent.
     */
    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline(); // 建立pipeline
    }
}

下面是pipeline的具體實現類,可以看到在初始化pipeline的時候,也初始化了head/tail兩個變數, 同時改變了指向

public class DefaultChannelPipeline implements ChannelPipeline {
    
    // pipeline裡面
    final AbstractChannelHandlerContext head;
    final AbstractChannelHandlerContext tail;

    private final Channel channel;
    private final ChannelFuture succeededFuture;
    private final VoidChannelPromise voidPromise;
    private final boolean touch = ResourceLeakDetector.isEnabled();
    private boolean registered;

    protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");// 這個方法值得借鑑
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);

        // 建立兩個節點
        tail = new TailContext(this); //AbstractChannelHandlerContext
        head = new HeadContext(this); //AbstractChannelHandlerContext的子類

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

pipeline裡面儲存著連結串列的頭結點和尾節點,因為很容易向連結串列中新增元素,具體方法如下:

    // 這個方法向連結串列裡面新增節點
    private void addLast0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext prev = tail.prev;
        newCtx.prev = prev;
        newCtx.next = tail;
        prev.next = newCtx;
        tail.prev = newCtx;
    }

在執行handler的過程中需要一個一個的遍歷連結串列,具體方法如下:

 private AbstractChannelHandlerContext findContextInbound(int mask) {// 這個是從連結串列裡面獲取一個元素 那麼是怎麼新增進去的呢?這個方法見上面
        logger.info("findContextInbound-_-");
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while ((ctx.executionMask & mask) == 0);
        return ctx;
    }