Http-Netty-Rpc-Service系統改造:不要在springboot的啟動主線程中阻塞,nettyserver的postconstruct注解的init方法中不要寫future.channel().closeFuture().sync();


常規的demo級別的netty服務端的代碼寫法是這樣的:

try {
                //創建並初始化 Netty 服務端輔助啟動對象 ServerBootstrap
                ServerBootstrap serverBootstrap = RpcServer.this.initServerBootstrap(bossGroup, workerGroup);
                //綁定對應ip和端口,同步等待成功
                ChannelFuture future = serverBootstrap.bind(port).sync();
                LOGGER.info("rpc server 已啟動,端口:{}", port);
                //等待服務端監聽端口關閉
                future.channel().closeFuture().sync();
            } catch (InterruptedException i) {
                LOGGER.error("rpc server 出現異常,端口:{}, cause:", port, i.getMessage());
            } finally {
                //優雅退出,釋放 NIO 線程組
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }

在這里面future.channel().closeFuture().sync();這個語句的主要目的是,方便測試,方便寫一個非springboot的demo,比如一個簡單地junit test方法,closeFuture().sync()可以阻止junit test將server關閉,同時停止test應用的時候也不需要手動再調用關閉服務器的方法workerGroup.shutdownGracefully()...。這樣設計在測試時省心。

但是,當將nettyserver聯系到springboot應用的啟動時,例如nettyserver設置為@Component,當springboot掃描到nettyserver時,springboot主線程執行到nettyserver的postconstruct注解的方法,然后發生了

future.channel().closeFuture().sync();
這樣導致springboot主線程阻塞,無法繼續加載剩下的bean,
更糟糕的是,如果springboot還添加了springboot-web的依賴(自帶tomcat容器),那么被阻塞后將無法啟動tomcat servlet engine和webapplicationcontext.

所以不能簡單地在nettyserver中的構造方法/init方法中寫future.channel().closeFuture().sync();和workerGroup.shutdownGracefully().

只需在構造方法/init方法中bootstrap.bind(port),這是異步的,不會阻塞springboot主線程。

而將stop方法單獨抽取出來。

需要注意的是,即使直接關閉springboot應用,不手動調用上面的stop方法,nettyserver也會將之前綁定的端口解除,為了保險起見,可以將stop方法添加@predestroy注解

 





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM