標籤:網路 java nio netty
前言:我們自己使用java nio開發網路程式是非常繁瑣的,netty為我們做好了一切,其中ServerBootstrap是一個啟動輔助類,瞭解它我們就能開發出簡單的nio 服務端程式。
不理解Nio中channel和handler等可參考上一篇文章
學習 java netty (一) – java nio
ServerBootstrap():
//建立一個ServerBootstrap對象ServerBootstrap server = new ServerBootstrap;
ServerBootstrap只有一個無參建構函式,這裡使用了構建器模式,原因是ServerBootstrap的參數過多,構建器模式就是用來處理建構函式參數過多而導致需要多個建構函式的問題。
簡單來看:
當參數過多我們寫出來的建構函式可能是
ServerBootstrap(int i);
ServerBootstrap(int i, double b);
ServerBootstrap(int i, double b, char c);
…
使用構建器模式後
ServerBootstrap(); 只有一個無參建構函式,其餘需要構建的部分我們寫到成員函數裡,那麼使用起來就像這樣。
ServerBootstrap server = ServerBootstrap();
server
.construct1()
.construct2()
.consturct3()
…
當然也可以
server.construct1().construct3()…
我們使用哪個構建哪個即可,這就是構建器模式
構建器模式缺點:
寫起來比較複雜,用起來開銷很大,只適用於建構函式參數過多的情況。
注意構建器模式要返回this
ServerBootstrap繼承自AbstractBootstrap
看一下ServerBootstrap class內部的變數和方法
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel>{ //記錄異常日誌等錯誤,用了java的反射機制和原廠模式 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class); //netty4.0引入了名為ChannelOption的新的類型,它提供了型別安全地訪問socket選項。ChannelOption class內部就是socket通訊端配置參數,例如SO_KEEPALIVE,SO_RECVBUF等 private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>(); //實體的屬性 private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>(); //事件迴圈,並綁定線程池 private volatile EventLoopGroup childGroup; //處理channel的handler private volatile ChannelHandler childHandler; //方法 //只有一個事件迴圈體,來接受accept和處理IO public ServerBootstrap group(EventLoopGroup group); //有兩個事件迴圈體,一個用來accept請求,另外一個用來處理clinet的io public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup); //設定channel屬性 public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value); //設定那些符合給定屬性的channel public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) ; //child處理channel的handler public ServerBootstrap childHandler(ChannelHandler childHandler); //return childGroup public EventLoopGroup childGroup(); //初始化並配置一些參數 void init(Channel channel) throws Exception public ServerBootstrap validate();
還有一些不太重要方法上面沒有列舉出來,還有些方法來自於父類AbstractBootstrap,代碼太長就不貼了,感興趣可以去git上看源碼
AbstractBootstrap.java
但是從ServerBootstrap啟動輔助類和ServerBootstrap class內部的參數和介面可以看出ServerBootstrap主要是用來佈建服務端的。僅僅使用了一個對象ServerBootstrap就完成了複雜的服務端配置,讓我們編程簡化了許多。
看個例子:
public class EchoServer { private final int port; public EchoServer(int port) { this.port = port; } public void run() throws Exception{ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { //建立一個ServerBootstrap,下面開始配置 ServerBootstrap b = new ServerBootstrap(); //建立了兩個EventLoopGroup(線程池和selector,reactor模型)一個main loop一個child loop通過ServerBoootstrap的group方法組合起來 //接著通過option方法傳遞服務端NioServerSocketChannel(服務端通訊端)設定它的backlog參數。 //再通過handler設定服務端socket(ServerSocketChannel)的處理事件的handler是記錄日誌logger //最後childhandler設定每一個串連到服務端的socket(socketchannel)的handler(childhandler),是建立一個EchoServerHandler類去處理。(利用channelhandler我們可以完成功能定製) //channelpipeline負責管理和執行channelhandler,可以向channelpipeline中add添加channelhandler //(注意ServerBootstrap部分方法來自父類) b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { public void initChannel(SocketChannel ch) throws Exception { //abstractBoostStrap中的Handler是個工廠類,它為每個新接入的用戶端都建立一個新的Handler //下面代碼每新串連一個socket,都會建立一個EchoServerHandler System.out.println("hello"); ch.pipeline().addLast(new EchoServerHandler()); //ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO)); } }); //綁定連接埠,netty中所有IO操作都是非同步,它會立即返回,但不能保證完成操作 ChannelFuture f = b.bind(port).sync(); System.out.println("bind...."); f.channel().closeFuture().sync(); }catch(Exception e){ e.printStackTrace(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if(args.length > 0){ port = Integer.parseInt(args[0]); }else{ port = 10000; } new EchoServer(port).run(); }}
上面僅僅一行代碼就完成了很多參數的設定,為我們編程簡化了很多。
ServerBootstrap建立時序圖:
圖片非原創
補充原廠模式:
原廠模式利用java的反射,參數為Class<>,我們傳遞參數為.class(構建對象的類型)而不是類對象執行個體,然後根據需要在方法裡構建相應的對象,這也延遲了對象的建立,簡單來說就是我們需要什麼類型的物品,告訴工廠,工廠產生給我們相應的實體。
backlog等參數的含義
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
學習 java netty (二) -- ServerBootstrap