Netty中的handler是如何添加到pipeline中的?


把源碼梳理清楚(Netty hello world之添加handler)

DefaultChannelPipeline.addLast(ChannelHandler … handlers)

  • 對於添加到pipeline中的非null handler,先生成這個handler名字。名字的生成規則如下【DefaultChannelPipeline.generateName】:

    1. 根據當前的線程ID獲取在nameCaches中的緩存【nameCaches是一個靜態WeakHashMap的數組,數組長度為當前運行jvm的邏輯核數】

    2. 使用synchronized鎖住查詢的代碼,如果cache中根據handler的class名字沒有查到,生成新的名字然【新名字獲取方式為Class獲取的包名和類名,並在后面拼接一個 #0】后將名字放入cache

    3. 檢查當前名字是否已經存在,如果存在了就把后綴0一直自增到沒有這個名字為止,然后handler賦為這個名字【如果用戶在一個pipeline里面多次添加同一個handler,新的名字就需要自增–但是這里面name沒有再放入name2ctx】

synchronized (this) {
            // 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 (name2ctx.containsKey(name)) {
                String baseName = name.substring(0, name.length() - 1); // Strip the trailing '0'.
                for (int i = 1;; i ++) {
                    String newName = baseName + i;
                    if (!name2ctx.containsKey(newName)) {
                        name = newName; // bug?導致后面重復?
                        break;
                    }
                }
            }
        }
  • 鎖住添加的代碼塊,如果名字重復就拋異常

  • 新建DefaultChannelHandlerContext,優先執行父類構造方法,判斷當前handler是Inbound還是Outbound類型

  • 執行AbstractChannelHandlerContext構造方法:將pipeline的channel賦值給context的channel【這樣context和pipeline實際共用同一個channel】,同樣賦值pipeline,name,inbound,outbound,如果有構造過程中有group,則獲取pipeline中的childExecutor並賦值給context

  • 回到執行子類的構造函數DefaultChannelHandlerContext,即賦值context的handler為自己要添加的handler

  • DefaultChannelPipeline.addLast0,添加handler到pipeline中,校驗被多個pipeline使用的handler【通過handler的add字段識別】是否有用Sharable標識,是多個pipeline共享沒有sharable就拋出異常,否則將新建的context添加到pipeline的tail的前面。 從源碼可以看出pipeline實際上就是一個雙向鏈表

 AbstractChannelHandlerContext prev = tail.prev;
 newCtx.prev = prev;
 newCtx.next = tail;
 prev.next = newCtx;
 tail.prev = newCtx;
  • 將handler的名字放入name2ctx【本質是一個hashMap】中

  • 如果channel已經注冊過,並且contex的executor不是當前線程【對於GlobalEventExecutor和SingleThreadEventExecutor來講是判斷線程是否一致,其它是直接返回true】,在context的executor中添加一個新的任務【SingleThreadEventExecutor.execute】:任務之行callHandlerAdded0 ;如果注冊過或者context是當前的線程則直接執行callHandlerAdded0

  • DefaultChannelPipeline.callHandlerAdded0:執行handler【自己實現的】的handlerAdded方法,來關聯handler和context,對於ChannelInboundHandlerAdapter來說什么都沒有做,用戶可以自己來實現接口做監聽,這個時候已經可以開始處理事件了。在調用handlerAdded的過程中,如果發生了異常,就執行刪除handler,邏輯類似添加,只不過最后觸發的事件是handlerRemoved

往executor中添加任務的邏輯


以SingleThreadEventExecutor.execute為例

  1. 獲取inEventLoop標識,判斷當前執行線程是不是executor線程

  2. 是executor線程:從STATE_UPDATER【它是一個jdk的AtomicIntegerFieldUpdater】中查到當前executor的值,如果狀態值大於等於ST_SHUTDOWN,認為當前executor已經關閉,則直接拋出異常;否則將task添加到executor的taskQueue【它默認是一個存放Runnable的LinkedBlockingQueue】中

  3. 不是executor線程:從STATE_UPDATER中查到當前的executor,如果發現它沒有啟動,就設置為已經啟動,並往delayedTaskQueue【它是一個PriorityQueue】中添加一個ScheduledFutureTask【設置deadlineNanos為距離啟動時間后延續1納秒,periodNanos】,然后啟動當前executor的線程,啟動線程實際上就是執行線程子類的run方法【后續補充executor的線程執行邏輯】


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com