你一定看得懂的Netty客戶端啓動源碼分析!

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面已經講解了"},{"type":"codeinline","content":[{"type":"text","text":"NIO"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"服務端啓動,這一講是"},{"type":"codeinline","content":[{"type":"text","text":"Client"}]},{"type":"text","text":"的啓動過程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"源碼系列的文章依舊還是遵循大白話+畫圖的風格來講解,本文"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"源碼及以後的文章版本都基於:"},{"type":"text","marks":[{"type":"strong"}],"text":"4.1.22.Final"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本篇是以"},{"type":"codeinline","content":[{"type":"text","text":"NettyClient"}]},{"type":"text","text":"啓動爲切入點,帶大家一步步進入"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"源碼的世界。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Client啓動流程揭祕"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1、探祕的入口:netty-client demo"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏用"},{"type":"codeinline","content":[{"type":"text","text":"netty-exmaple"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"EchoClient"}]},{"type":"text","text":"來作爲例子:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public final class EchoClient {\n public static void main(String[] args) throws Exception {\n EventLoopGroup group = new NioEventLoopGroup();\n try {\n Bootstrap b = new Bootstrap();\n b.group(group)\n .channel(NioSocketChannel.class)\n .option(ChannelOption.TCP_NODELAY, true)\n .handler(new ChannelInitializer() {\n @Override\n public void initChannel(SocketChannel ch) throws Exception {\n ChannelPipeline p = ch.pipeline();\n p.addLast(new EchoClientHandler());\n }\n });\n\n ChannelFuture f = b.connect(HOST, PORT).sync();\n\n f.channel().closeFuture().sync();\n } finally {\n group.shutdownGracefully();\n }\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼沒有什麼獨特的地方,我們上一篇文章時也梳理過"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"網絡編程的一些套路,這裏就不再贅述了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(忘記的小朋友可以查看"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"系列文章中查找~)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面的客戶端代碼雖然簡單, 但是卻展示了"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":" 客戶端初始化時所需的所有內容:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":":"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"服務端或者客戶端,都必須指定"},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":",客戶端指定的是"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Bootstrap"}]},{"type":"text","text":": "},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"客戶端啓動類,負責客戶端的啓動和初始化過程"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"channel()"}]},{"type":"text","text":"類型:指定"},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":"的類型,因爲這裏是客戶端,所以使用的是"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":",服務端會使用"},{"type":"codeinline","content":[{"type":"text","text":"NioServerSocketChannel"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Handler"}]},{"type":"text","text":":設置數據的處理器"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"bootstrap.connect()"}]},{"type":"text","text":": 客戶端連接"},{"type":"codeinline","content":[{"type":"text","text":"netty"}]},{"type":"text","text":"服務的方法"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2、NioEventLoopGroup 流程解析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們先從"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]},{"type":"text","text":"開始,一行行代碼解析,先看看其類結構:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/98/9862caaafb3fe3aecd299a9a77db6e8d.png","alt":"NioEventLoopGroup類結構.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面是大致的類結構,而 "},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":" 又繼承自"},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":",所以類的大致結構我們可想而知。這裏一些核心邏輯會在"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":"中,包含"},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":"的創建和初始化操作等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着從"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]},{"type":"text","text":"構造方法開始看起,一步步往下跟("},{"type":"text","marks":[{"type":"strong"}],"text":"代碼都只展示重點的部分,省去很多暫時不需要關心的代碼,以下代碼都遵循這個原則"},{"type":"text","text":"):"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"EventLoopGroup group = new NioEventLoopGroup();\n\npublic NioEventLoopGroup() {\n this(0);\n}\n\npublic NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider) {\n this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);\n}\n\nprotected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {\n super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏通過調用"},{"type":"codeinline","content":[{"type":"text","text":"this()"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"super()"}]},{"type":"text","text":"方法一路往下傳遞,期間會構造一些默認屬性,一直傳遞到"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":"類中,接着往西看。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.1、MultithreadEventExecutorGroup"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面構造函數有一個重要的參數傳遞:"},{"type":"codeinline","content":[{"type":"text","text":"DEFAULT_EVENT_LOOP_THREADS"}]},{"type":"text","text":",這個值默認是"},{"type":"codeinline","content":[{"type":"text","text":"CPU核數 * 2"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲什麼要傳遞這個參數呢?我們之前說過"},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":"可以理解成一個線程池,"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":"有一個線程數組"},{"type":"codeinline","content":[{"type":"text","text":"EventExecutor[] children"}]},{"type":"text","text":"屬性,而傳遞過來的"},{"type":"codeinline","content":[{"type":"text","text":"DEFAULT_EVENT_LOOP_THREADS"}]},{"type":"text","text":"就是數組的長度。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先看下"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":"中的構造方法:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"protected MultithreadEventExecutorGroup(int nThreads, Executor executor,\n EventExecutorChooserFactory chooserFactory, Object... args) {\n if (executor == null) {\n executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());\n }\n \n children = new EventExecutor[nThreads];\n \n for (int i = 0; i < nThreads; i ++) {\n children[i] = newChild(executor, args);\n }\n \n // ... 省略\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這段代碼執行邏輯可以理解爲:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過"},{"type":"codeinline","content":[{"type":"text","text":"ThreadPerTaskExecutor"}]},{"type":"text","text":"構造一個"},{"type":"codeinline","content":[{"type":"text","text":"Executor"}]},{"type":"text","text":"執行器,後面會細說,裏面包含了線程執行的"},{"type":"codeinline","content":[{"type":"text","text":"execute()"}]},{"type":"text","text":"方法"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着創建一個"},{"type":"codeinline","content":[{"type":"text","text":"EventExecutor"}]},{"type":"text","text":"數組對象,大小爲傳遞進來的"},{"type":"codeinline","content":[{"type":"text","text":"threads"}]},{"type":"text","text":"數量,這個所謂的"},{"type":"codeinline","content":[{"type":"text","text":"EventExecutor"}]},{"type":"text","text":"可以理解爲我們的"},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":",在這個demo中就是"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoop"}]},{"type":"text","text":"對象"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後調用 "},{"type":"codeinline","content":[{"type":"text","text":"newChild"}]},{"type":"text","text":" 方法逐個初始化"},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":"對象"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面只是大概說了下"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":"中的構造方法做的事情,後面還會一個個詳細展開,先不用着急,我們先有個整體的認知就好。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再回到"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":"中的構造方法入參中,有個"},{"type":"codeinline","content":[{"type":"text","text":"EventExecutorChooserFactory"}]},{"type":"text","text":"對象,這裏面是有個很亮眼的細節設計,通過它我們來洞悉"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"的良苦用心。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.1、亮點設計:DefaultEventExecutorChooserFactory"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4e/4ef714a9050f930516467245ac2d1122.png","alt":"EventExecutorChooserFactory.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"EventExecutorChooserFactory"}]},{"type":"text","text":"這個類的作用是用來選擇"},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":"執行器的,我們知道"},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":"是一個包含了"},{"type":"codeinline","content":[{"type":"text","text":"CPU * 2"}]},{"type":"text","text":"個數量的"},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":"數組對象,那每次選擇"},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":"來執行任務是選擇數組中的哪一個呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們看一下這個類的具體實現,"},{"type":"codeinline","content":[{"type":"text","text":"紅框中"}]},{"type":"text","text":"都是需要重點查看的地方:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/20/2070312fa6d0f77f93eb72270df2bae3.png","alt":"輪詢算法實現器.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"DefaultEventExecutorChooserFactory"}]},{"type":"text","text":"是一個選擇器工廠類,調用裏面的"},{"type":"codeinline","content":[{"type":"text","text":"next()"}]},{"type":"text","text":"方法達到一個輪詢選擇的目的。"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數組的長度是length,執行第n次,取數組中的哪個元素就是對length取餘"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/32/32266ba54efd0420782b912ce7e8768d.png","alt":"w9llHf.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"繼續回到代碼的實現,這裏的優化就是在於先通過"},{"type":"codeinline","content":[{"type":"text","text":"isPowerOfTwo()"}]},{"type":"text","text":"方法判斷數組的長度是否爲2的n次冪,判斷的方式很巧妙,使用"},{"type":"codeinline","content":[{"type":"text","text":"val & -val == val"}]},{"type":"text","text":",這裏我不做過多的解釋,網上還有很多判斷2的n次冪的優秀解法,我就不班門弄斧了。("},{"type":"text","marks":[{"type":"strong"}],"text":"可參考:"},{"type":"link","attrs":{"href":"https://leetcode-cn.com/problems/power-of-two/solution/2de-mi-by-leetcode/","title":null},"content":[{"type":"text","text":"https://leetcode-cn.com/problems/power-of-two/solution/2de-mi-by-leetcode/"}],"marks":[{"type":"strong"}]},{"type":"text","text":")"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然我認爲這裏還有更容易理解的一個算法:"},{"type":"codeinline","content":[{"type":"text","text":"x & (x - 1) == 0"}]},{"type":"text","text":" 大家可以看下面的圖就懂了,這裏就不延展了:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c5/c5b75bfdfae632d3384461fb50371844.png","alt":"2的冪次方算法.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"BUT!!! 這裏爲什麼要去煞費苦心的判斷數組的長度是2的n次冪?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不知道小夥伴們是否還記得"},{"type":"text","marks":[{"type":"strong"}],"text":"大明湖畔"},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"HashMap"}]},{"type":"text","text":"?一般我們要求"},{"type":"codeinline","content":[{"type":"text","text":"HashMap"}]},{"type":"text","text":"數組的長度需要是2的n次冪,因爲在"},{"type":"codeinline","content":[{"type":"text","text":"key"}]},{"type":"text","text":"值尋找數組位置的方法:"},{"type":"codeinline","content":[{"type":"text","text":"(n - 1) & hash"}]},{"type":"text","text":" n是數組長度,這裏如果數組長度是2的n次冪就可以通過位運算來提升性能,當"},{"type":"codeinline","content":[{"type":"text","text":"length"}]},{"type":"text","text":"爲2的n次冪時下面公式是等價的:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"n & (length - 1) <=> n % length"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還記得上面說過,數組的長度默認都是"},{"type":"codeinline","content":[{"type":"text","text":"CPU * 2"}]},{"type":"text","text":",而一般服務器CPU核心數都是2、4、8、16等等,所以這一個小優化就很實用了,再仔細想想,原來數組長度的初始化也是很講究的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏位運算的好處就是效率遠遠高於與運算,"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"針對於這個小細節都做了優化,真是太棒了。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.3、線程執行器:ThreadPerTaskExecutor"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着看下"},{"type":"codeinline","content":[{"type":"text","text":"ThreadPerTaskExecutor"}]},{"type":"text","text":"線程執行器,每次執行任務都會通過它來創建一個線程實體。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public final class ThreadPerTaskExecutor implements Executor {\n private final ThreadFactory threadFactory;\n\n public ThreadPerTaskExecutor(ThreadFactory threadFactory) {\n if (threadFactory == null) {\n throw new NullPointerException(\"threadFactory\");\n }\n this.threadFactory = threadFactory;\n }\n\n @Override\n public void execute(Runnable command) {\n threadFactory.newThread(command).start();\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"傳遞進來的"},{"type":"codeinline","content":[{"type":"text","text":"threadFactory"}]},{"type":"text","text":"爲"},{"type":"codeinline","content":[{"type":"text","text":"DefaultThreadFactory"}]},{"type":"text","text":",這裏面會構造"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoop"}]},{"type":"text","text":"線程命名規則爲"},{"type":"codeinline","content":[{"type":"text","text":"nioEventLoop-1-xxx"}]},{"type":"text","text":",我們就不細看這個了。當線程執行的時候會調用"},{"type":"codeinline","content":[{"type":"text","text":"execute()"}]},{"type":"text","text":"方法,這裏會創建一個"},{"type":"codeinline","content":[{"type":"text","text":"FastThreadLocalThread"}]},{"type":"text","text":"線程,具體看代碼:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public class DefaultThreadFactory implements ThreadFactory {\n @Override\n public Thread newThread(Runnable r) {\n Thread t = newThread(FastThreadLocalRunnable.wrap(r), prefix + nextId.incrementAndGet());\n return t;\n }\n\n protected Thread newThread(Runnable r, String name) {\n return new FastThreadLocalThread(threadGroup, r, name);\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏通過"},{"type":"codeinline","content":[{"type":"text","text":"newThread()"}]},{"type":"text","text":"來創建一個線程,然後初始化線程對象數據,最終會調用到"},{"type":"codeinline","content":[{"type":"text","text":"Thread.init()"}]},{"type":"text","text":"中。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.4、EventLoop初始化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着繼續看"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":"構造方法:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"protected MultithreadEventExecutorGroup(int nThreads, Executor executor,\n EventExecutorChooserFactory chooserFactory, Object... args) {\n children = new EventExecutor[nThreads];\n for (int i = 0; i < nThreads; i ++) {\n children[i] = newChild(executor, args);\n // .... 省略部分代碼\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面代碼的最後一部分是 "},{"type":"codeinline","content":[{"type":"text","text":"newChild"}]},{"type":"text","text":" 方法, 這個是一個抽象方法, 它的任務是實例化 "},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":" 對象. 我們跟蹤一下它的代碼, 可以發現, 這個方法在 "},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]},{"type":"text","text":" 類中實現了, 其內容很簡單:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@Override\nprotected EventLoop newChild(Executor executor, Object... args) throws Exception {\n return new NioEventLoop(this, executor, (SelectorProvider) args[0],\n ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);\n}\n\nNioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,\n SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {\n super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);\n if (selectorProvider == null) {\n throw new NullPointerException(\"selectorProvider\");\n }\n if (strategy == null) {\n throw new NullPointerException(\"selectStrategy\");\n }\n provider = selectorProvider;\n final SelectorTuple selectorTuple = openSelector();\n selector = selectorTuple.selector;\n unwrappedSelector = selectorTuple.unwrappedSelector;\n selectStrategy = strategy;\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其實就是實例化一個 "},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoop"}]},{"type":"text","text":" 對象, 然後返回。"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoop"}]},{"type":"text","text":"構造函數中會保存"},{"type":"codeinline","content":[{"type":"text","text":"provider"}]},{"type":"text","text":"和事件輪詢器"},{"type":"codeinline","content":[{"type":"text","text":"selector"}]},{"type":"text","text":",在其父類中還會創建一個"},{"type":"codeinline","content":[{"type":"text","text":"MpscQueue隊列"}]},{"type":"text","text":",然後保存線程執行器"},{"type":"codeinline","content":[{"type":"text","text":"executor"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再回過頭來想一想,"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":" 內部維護了一個 "},{"type":"codeinline","content":[{"type":"text","text":"EventExecutor[] children"}]},{"type":"text","text":"數組, "},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":" 的 "},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":" 的實現機制其實就建立在 "},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":" 之上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每當 "},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":" 需要一個 "},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":" 時, 會調用 "},{"type":"codeinline","content":[{"type":"text","text":"next()"}]},{"type":"text","text":" 方法從"},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":"數組中獲取一個可用的 "},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":"對象。其中"},{"type":"codeinline","content":[{"type":"text","text":"next"}]},{"type":"text","text":"方法的實現是通過"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup.next()"}]},{"type":"text","text":"來完成的,就是用的上面有過講解的通過輪詢算法來計算得出的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後總結一下整個 "},{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":" 的初始化過程:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/83/83cfee3110b316ace0890ade0ae16527.png","alt":"EventLoopGroup構造流程.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"EventLoopGroup"}]},{"type":"text","text":"(其實是"},{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":") 內部維護一個類型爲 "},{"type":"codeinline","content":[{"type":"text","text":"EventExecutor children"}]},{"type":"text","text":" 數組,數組長度是"},{"type":"codeinline","content":[{"type":"text","text":"nThreads"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果我們在實例化 "},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]},{"type":"text","text":" 時, 如果指定線程池大小, 則 "},{"type":"codeinline","content":[{"type":"text","text":"nThreads"}]},{"type":"text","text":" 就是指定的值, 反之是"},{"type":"codeinline","content":[{"type":"text","text":"處理器核心數 * 2"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"MultithreadEventExecutorGroup"}]},{"type":"text","text":" 中會調用 "},{"type":"codeinline","content":[{"type":"text","text":"newChild"}]},{"type":"text","text":" 抽象方法來初始化 "},{"type":"codeinline","content":[{"type":"text","text":"children"}]},{"type":"text","text":" 數組"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"抽象方法 "},{"type":"codeinline","content":[{"type":"text","text":"newChild"}]},{"type":"text","text":" 是在 "},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]},{"type":"text","text":" 中實現的, 它返回一個 "},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoop"}]},{"type":"text","text":" 實例."}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"NioEventLoop"}]},{"type":"text","text":" 屬性:"},{"type":"codeinline","content":[{"type":"text","text":"SelectorProvider provider"}]},{"type":"text","text":" 屬性: "},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]},{"type":"text","text":" 構造器中通過 "},{"type":"codeinline","content":[{"type":"text","text":"SelectorProvider.provider()"}]},{"type":"text","text":" 獲取一個 "},{"type":"codeinline","content":[{"type":"text","text":"SelectorProvider"}]},{"type":"codeinline","content":[{"type":"text","text":"Selector selector"}]},{"type":"text","text":" 屬性: "},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoop"}]},{"type":"text","text":" 構造器中通過調用通過 "},{"type":"codeinline","content":[{"type":"text","text":"selector = provider.openSelector()"}]},{"type":"text","text":" 獲取一個 "},{"type":"codeinline","content":[{"type":"text","text":"selector"}]},{"type":"text","text":" 對象."}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.5、NioSocketChannel"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"中,"},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":"是對"},{"type":"codeinline","content":[{"type":"text","text":"Socket"}]},{"type":"text","text":"的抽象,每當"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"建立一個連接後,都會有一個與其對應的"},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":"實例。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們在開頭的"},{"type":"codeinline","content":[{"type":"text","text":"Demo"}]},{"type":"text","text":"中,設置了"},{"type":"codeinline","content":[{"type":"text","text":"channel(NioSocketChannel.class)"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":"的類結構如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/55/554e3e1f78784c620c2e847cb6b417f0.png","alt":"NioSocketChannel類結構.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着分析代碼,當我們調用"},{"type":"codeinline","content":[{"type":"text","text":"b.channel()"}]},{"type":"text","text":"時實際上會進入"},{"type":"codeinline","content":[{"type":"text","text":"AbstractBootstrap.channel()"}]},{"type":"text","text":"邏輯,接着看"},{"type":"codeinline","content":[{"type":"text","text":"AbstractBootstrap"}]},{"type":"text","text":"中代碼:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public B channel(Class extends C> channelClass) {\n if (channelClass == null) {\n throw new NullPointerException(\"channelClass\");\n }\n return channelFactory(new ReflectiveChannelFactory(channelClass));\n}\n\npublic ReflectiveChannelFactory(Class extends T> clazz) {\n if (clazz == null) {\n throw new NullPointerException(\"clazz\");\n }\n this.clazz = clazz;\n}\n\npublic B channelFactory(ChannelFactory extends C> channelFactory) {\n if (channelFactory == null) {\n throw new NullPointerException(\"channelFactory\");\n }\n if (this.channelFactory != null) {\n throw new IllegalStateException(\"channelFactory set already\");\n }\n\n this.channelFactory = channelFactory;\n return self();\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到,這裏"},{"type":"codeinline","content":[{"type":"text","text":"ReflectiveChannelFactory"}]},{"type":"text","text":"其實就是返回我們指定的"},{"type":"codeinline","content":[{"type":"text","text":"channelClass:NioSocketChannel"}]},{"type":"text","text":", 然後指定"},{"type":"codeinline","content":[{"type":"text","text":"AbstractBootstrap"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"channelFactory = new ReflectiveChannelFactory()"}]},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.6、Channel初始化流程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到了這一步,我們已經知道"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"channel()"}]},{"type":"text","text":"的流程,接着來看看"},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":"的 初始化流程,這也是"},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":"客戶端啓動的的核心流程之一:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"ChannelFuture f = b.connect(HOST, PORT).sync();\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着就開始從"},{"type":"codeinline","content":[{"type":"text","text":"b.connect()"}]},{"type":"text","text":"爲入口一步步往後跟,先看下"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":"構造的整體流程:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1a/1a88bb5912f3786a32043a621b9e1537.png","alt":"NioSocketChannel構造流程.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從"},{"type":"codeinline","content":[{"type":"text","text":"connet"}]},{"type":"text","text":"往後梳理下整體流程:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Bootstrap.connect -> Bootstrap.doResolveAndConnect -> AbstractBootstrap.initAndRegister"}]}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"final ChannelFuture initAndRegister() {\n Channel channel = channelFactory.newChannel();\n init(channel);\n \n ChannelFuture regFuture = config().group().register(channel);\n return regFuture;\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了更易讀,這裏代碼都做了簡化,只保留了一些重要的代碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緊接着我們看看"},{"type":"codeinline","content":[{"type":"text","text":"channelFactory.newChannel()"}]},{"type":"text","text":"做了什麼,這裏"},{"type":"codeinline","content":[{"type":"text","text":"channelFactory"}]},{"type":"text","text":"是"},{"type":"codeinline","content":[{"type":"text","text":"ReflectiveChannelFactory"}]},{"type":"text","text":",我們在上面的章節分析過:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@Override\npublic T newChannel() {\n try {\n return clazz.getConstructor().newInstance();\n } catch (Throwable t) {\n throw new ChannelException(\"Unable to create Channel from class \" + clazz, t);\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的"},{"type":"codeinline","content":[{"type":"text","text":"clazz"}]},{"type":"text","text":"是"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":",同樣是在上面章節講到過,這裏是調用"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":"的構造函數然後初始化一個"},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":"實例。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public class NioSocketChannel extends AbstractNioByteChannel implements io.netty.channel.socket.SocketChannel {\n public NioSocketChannel() {\n this(DEFAULT_SELECTOR_PROVIDER);\n }\n\n public NioSocketChannel(SelectorProvider provider) {\n this(newSocket(provider));\n }\n\n private static SocketChannel newSocket(SelectorProvider provider) {\n try {\n return provider.openSocketChannel();\n } catch (IOException e) {\n throw new ChannelException(\"Failed to open a socket.\", e);\n }\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏其實也很簡單,就是創建一個"},{"type":"codeinline","content":[{"type":"text","text":"Java NIO SocketChannel"}]},{"type":"text","text":"而已,接着看看"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":"的父類還做了哪些事情,這裏梳理下類的關係:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"NioSocketChannel -> extends AbstractNioByteChannel -> exntends AbstractNioChannel"}]}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public abstract class AbstractNioChannel extends AbstractChannel {\n protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {\n super(parent, ch, SelectionKey.OP_READ);\n }\n\n protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {\n super(parent);\n ch.configureBlocking(false);\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏會調用父類的構造參數,並且傳遞"},{"type":"codeinline","content":[{"type":"text","text":"readInterestOp = SelectionKey.OP_READ:"}]},{"type":"text","text":",這裏還有一個很重要的點,配置 "},{"type":"codeinline","content":[{"type":"text","text":"Java NIO SocketChannel"}]},{"type":"text","text":" 爲非阻塞的,我們之前在"},{"type":"codeinline","content":[{"type":"text","text":"NIO"}]},{"type":"text","text":"章節的時候講解過,這裏也不再贅述。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接着繼續看"},{"type":"codeinline","content":[{"type":"text","text":"AbstractChannel"}]},{"type":"text","text":"的構造函數:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {\n protected AbstractChannel(Channel parent) {\n this.parent = parent;\n id = newId();\n unsafe = newUnsafe();\n pipeline = newChannelPipeline();\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏創建一個"},{"type":"codeinline","content":[{"type":"text","text":"ChannelId"}]},{"type":"text","text":",創建一個"},{"type":"codeinline","content":[{"type":"text","text":"Unsafe"}]},{"type":"text","text":"對象,這裏的"},{"type":"codeinline","content":[{"type":"text","text":"Unsafe"}]},{"type":"text","text":"並不是Java中的Unsafe,後面也會講到。然後創建一個"},{"type":"codeinline","content":[{"type":"text","text":"ChannelPipeline"}]},{"type":"text","text":",後面也會講到,到了這裏,一個完整的"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":" 就初始化完成了,我們再來總結一下:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":" 的 "},{"type":"codeinline","content":[{"type":"text","text":"SocketChannel"}]},{"type":"text","text":" 會與 "},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":" 原生的 "},{"type":"codeinline","content":[{"type":"text","text":"SocketChannel"}]},{"type":"text","text":" 綁定在一起;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"會註冊 "},{"type":"codeinline","content":[{"type":"text","text":"Read"}]},{"type":"text","text":" 事件;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"會爲每一個 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 分配一個 "},{"type":"codeinline","content":[{"type":"text","text":"channelId"}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"會爲每一個 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 創建一個"},{"type":"codeinline","content":[{"type":"text","text":"Unsafe"}]},{"type":"text","text":"對象;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"會爲每一個 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 分配一個 "},{"type":"codeinline","content":[{"type":"text","text":"ChannelPipeline"}]},{"type":"text","text":";"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.7、Channel 註冊流程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還是回到最上面"},{"type":"codeinline","content":[{"type":"text","text":"initAndRegister"}]},{"type":"text","text":"方法,我們上面都是在分析裏面"},{"type":"codeinline","content":[{"type":"text","text":"newChannel"}]},{"type":"text","text":"的操作,這個方法是"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":"創建的一個流程,接着我們在繼續跟"},{"type":"codeinline","content":[{"type":"text","text":"init()"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"register()"}]},{"type":"text","text":"的過程:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" public abstract class AbstractBootstrap, C extends Channel> implements Cloneable {\n final ChannelFuture initAndRegister() {\n Channel channel = channelFactory.newChannel();\n init(channel);\n ChannelFuture regFuture = config().group().register(channel);\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"init()"}]},{"type":"text","text":"就是將一些參數"},{"type":"codeinline","content":[{"type":"text","text":"options"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"attrs"}]},{"type":"text","text":"設置到"},{"type":"codeinline","content":[{"type":"text","text":"channel"}]},{"type":"text","text":"中,我們重點需要看的是"},{"type":"codeinline","content":[{"type":"text","text":"register"}]},{"type":"text","text":"方法,其調用鏈爲:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"AbstractBootstrap.initAndRegister -> MultithreadEventLoopGroup.register -> SingleThreadEventLoop.register -> AbstractUnsafe.register"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏最後到了"},{"type":"codeinline","content":[{"type":"text","text":"unsafe"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"register()"}]},{"type":"text","text":"方法,最終調用到"},{"type":"codeinline","content":[{"type":"text","text":"AbstractNioChannel.doRegister()"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@Override\nprotected void doRegister() throws Exception {\n boolean selected = false;\n for (;;) {\n selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);\n return;\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"javaChannel()"}]},{"type":"text","text":"就是"},{"type":"codeinline","content":[{"type":"text","text":"Java NIO"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"SocketChannel"}]},{"type":"text","text":",這裏是將"},{"type":"codeinline","content":[{"type":"text","text":"SocketChannel"}]},{"type":"text","text":"註冊到與"},{"type":"codeinline","content":[{"type":"text","text":"eventLoop"}]},{"type":"text","text":"相關聯的"},{"type":"codeinline","content":[{"type":"text","text":"selector"}]},{"type":"text","text":"上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/28/28fa6daecc03d6bf76a4b4cf819ffb2b.png","alt":"Channel註冊流程.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後我們整理一下服務啓動的整體流程:"}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"initAndRegister()"}]},{"type":"text","text":"初始化並註冊什麼呢?"}]}]}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"channelFactory.newChannel()"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過反射創建一個 "},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將 "},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":" 原生 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 綁定到 "},{"type":"codeinline","content":[{"type":"text","text":"NettyChannel"}]},{"type":"text","text":" 中"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註冊 "},{"type":"codeinline","content":[{"type":"text","text":"Read"}]},{"type":"text","text":" 事件"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 分配 "},{"type":"codeinline","content":[{"type":"text","text":"id"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 創建 "},{"type":"codeinline","content":[{"type":"text","text":"unsafe"}]},{"type":"text","text":"對象"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 創建"},{"type":"codeinline","content":[{"type":"text","text":"ChannelPipeline"}]},{"type":"text","text":"(默認是 "},{"type":"codeinline","content":[{"type":"text","text":"head<=>tail"}]},{"type":"text","text":" 的雙向鏈表)"}]}]}]},{"type":"numberedlist","attrs":{"start":"2","normalizeStart":"2"},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"`init(channel)``"}]}]}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把 "},{"type":"codeinline","content":[{"type":"text","text":"Bootstrap"}]},{"type":"text","text":" 中的配置設置到 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 中"}]}]}]},{"type":"numberedlist","attrs":{"start":"3","normalizeStart":"3"},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"register(channel)"}]}]}]}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把 "},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":" 綁定到一個 "},{"type":"codeinline","content":[{"type":"text","text":"EventLoop"}]},{"type":"text","text":" 上"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把 "},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":" 原生 "},{"type":"codeinline","content":[{"type":"text","text":"Channel、Netty"}]},{"type":"text","text":" 的 "},{"type":"codeinline","content":[{"type":"text","text":"Channel、Selector"}]},{"type":"text","text":" 綁定到 "},{"type":"codeinline","content":[{"type":"text","text":"SelectionKey"}]},{"type":"text","text":" 中"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"觸發 "},{"type":"codeinline","content":[{"type":"text","text":"Register"}]},{"type":"text","text":" 相關的事件"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.8 unsafe初始化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面有提到過在初始化"},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":"的過程中會創建一個"},{"type":"codeinline","content":[{"type":"text","text":"Unsafe"}]},{"type":"text","text":"的對象,然後綁定到"},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":"上:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"protected AbstractChannel(Channel parent) {\n this.parent = parent;\n id = newId();\n unsafe = newUnsafe();\n pipeline = newChannelPipeline();\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"newUnsafe"}]},{"type":"text","text":"直接調用到了"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":"中的方法:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@Override\nprotected AbstractNioUnsafe newUnsafe() {\n return new NioSocketChannelUnsafe();\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannelUnsafe"}]},{"type":"text","text":"是"},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":"中的一個內部類,然後向上還有幾個父類繼承,這裏主要是對應到相關"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"底層的"},{"type":"codeinline","content":[{"type":"text","text":"Socket"}]},{"type":"text","text":"操作。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.9 pipeline初始化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們還是回到"},{"type":"codeinline","content":[{"type":"text","text":"pipeline"}]},{"type":"text","text":"初始化的過程,來看一下"},{"type":"codeinline","content":[{"type":"text","text":"newChannelPipeline()"}]},{"type":"text","text":"的具體實現:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"protected DefaultChannelPipeline newChannelPipeline() {\n return new DefaultChannelPipeline(this);\n}\n\nprotected DefaultChannelPipeline(Channel channel) {\n this.channel = ObjectUtil.checkNotNull(channel, \"channel\");\n succeededFuture = new SucceededChannelFuture(channel, null);\n voidPromise = new VoidChannelPromise(channel, true);\n\n tail = new TailContext(this);\n head = new HeadContext(this);\n\n head.next = tail;\n tail.prev = head;\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們調用 "},{"type":"codeinline","content":[{"type":"text","text":"DefaultChannelPipeline"}]},{"type":"text","text":" 的構造器, 傳入了一個 "},{"type":"codeinline","content":[{"type":"text","text":"channel"}]},{"type":"text","text":", 而這個 "},{"type":"codeinline","content":[{"type":"text","text":"channel"}]},{"type":"text","text":" 其實就是我們實例化的 "},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"DefaultChannelPipeline"}]},{"type":"text","text":" 會將這個 "},{"type":"codeinline","content":[{"type":"text","text":"NioSocketChannel"}]},{"type":"text","text":" 對象保存在"},{"type":"codeinline","content":[{"type":"text","text":"channel"}]},{"type":"text","text":" 字段中. "},{"type":"codeinline","content":[{"type":"text","text":"DefaultChannelPipeline"}]},{"type":"text","text":" 中, 還有兩個特殊的字段, 即 "},{"type":"codeinline","content":[{"type":"text","text":"head"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","text":"tail"}]},{"type":"text","text":", 而這兩個字段是一個雙向鏈表的頭和尾. 其實在 "},{"type":"codeinline","content":[{"type":"text","text":"DefaultChannelPipeline"}]},{"type":"text","text":" 中, 維護了一個以 "},{"type":"codeinline","content":[{"type":"text","text":"AbstractChannelHandlerContext"}]},{"type":"text","text":" 爲節點的雙向鏈表, 這個鏈表是 "},{"type":"codeinline","content":[{"type":"text","text":"Netty"}]},{"type":"text","text":" 實現 "},{"type":"codeinline","content":[{"type":"text","text":"Pipeline"}]},{"type":"text","text":" 機制的關鍵."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於 "},{"type":"codeinline","content":[{"type":"text","text":"DefaultChannelPipeline"}]},{"type":"text","text":" 中的雙向鏈表以及它所起的作用, 我們會在後續章節詳細講解。這裏只是對"},{"type":"codeinline","content":[{"type":"text","text":"pipeline"}]},{"type":"text","text":"做個初步的認識。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"HeadContext"}]},{"type":"text","text":" 的繼承層次結構如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a8/a883d9d3c5e7fb389180f84427e22d21.png","alt":"HeadContext繼承結構.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"TailContext"}]},{"type":"text","text":" 的繼承層次結構如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1a/1a9abd47b77f7cc45a885d5b7ee60521.png","alt":"TailContext繼承結構.png","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以看到, 鏈表中 "},{"type":"codeinline","content":[{"type":"text","text":"head"}]},{"type":"text","text":" 是一個 "},{"type":"codeinline","content":[{"type":"text","text":"ChannelOutboundHandler"}]},{"type":"text","text":", 而 "},{"type":"codeinline","content":[{"type":"text","text":"tail"}]},{"type":"text","text":" 則是一個 "},{"type":"codeinline","content":[{"type":"text","text":"ChannelInboundHandler"}]},{"type":"text","text":"."}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.0、客戶端connect過程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客戶端連接的入口方法還是在"},{"type":"codeinline","content":[{"type":"text","text":"Bootstrap.connect()"}]},{"type":"text","text":"中,上面也分析過一部分內容,請求的具體流程是:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Bootstrap.connect() -> AbstractChannel.coonnect() -> NioSocketChannel.doConnect()"}]}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public static boolean connect(final SocketChannel socketChannel, final SocketAddress remoteAddress)\n throws IOException {\n try {\n return AccessController.doPrivileged(new PrivilegedExceptionAction() {\n @Override\n public Boolean run() throws IOException {\n return socketChannel.connect(remoteAddress);\n }\n });\n } catch (PrivilegedActionException e) {\n throw (IOException) e.getCause();\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看到這裏,還是用"},{"type":"codeinline","content":[{"type":"text","text":"Java NIO SocketChannel"}]},{"type":"text","text":"發送的"},{"type":"codeinline","content":[{"type":"text","text":"connect"}]},{"type":"text","text":"請求進行客戶端連接請求。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本篇文章以一個"},{"type":"codeinline","content":[{"type":"text","text":"Netty Client demo"}]},{"type":"text","text":"爲入口,然後解析了"},{"type":"codeinline","content":[{"type":"text","text":"NioEventLoopGroup"}]},{"type":"text","text":"創建的流程、"},{"type":"codeinline","content":[{"type":"text","text":"Channel"}]},{"type":"text","text":"的創建和註冊的流程,以及客戶端發起"},{"type":"codeinline","content":[{"type":"text","text":"connect"}]},{"type":"text","text":"的具體流程,這裏對於很多細節並沒有很深的深入下去,這些會放到後續的源碼分析文章,敬請期待~"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"來自:https://www.cnblogs.com/wang-meng/p/13711756.html"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章