此次更新拖了很長時間,第一是本身生病了,第二是由於最開始這篇想寫的很大,而後構思了好久,發現不太合適把不少東西寫在一塊兒,因此作了點拆分,準備國慶前完成這篇博客。java
開門見山,先說下這篇文章能學到什麼git
上一篇咱們看了Bootstrap類的大體的組成,也瞭解了它的一些配置方法,其實都是在設置它的成員變量,有些是ServerBootstrap的也有是它的父類AbstractBootstrap的,在這裏,我以爲主要有下面幾個。github
固然,這些只是它的一些接口,具體有多種實現,除了Nio,它也有Bio等其餘版本的,繼承鏈也很複雜,這裏咱們先看下channel的實現。bootstrap
說到channel,它是Java Nio中的一個重要的成員,不過在netty中,channel是本身封裝的一個更抽象的東西,在Nio版本的實現中,它也維護了Java Nio的channel,不過這些都是後話了,咱們先看一下它的繼承鏈,這裏我本身畫了一個簡單的。
框架
這裏能夠看到,它的繼承有兩個分支,準確的說一條線是繼承抽象類,一條線是實現接口,這麼作,能夠說是netty設計上的考慮,一方面,它是nio的channel,可是同時它又是server端的channel,因此netty選擇了這樣作來實現。異步
看到這裏你可能會疑問,這個channel是netty本身封裝的,那他是怎麼和Nio的channel發生碰撞的呢?
首先,它在構造方法裏利用Java Nio的selectProvider 打開了一個socketChannel,而後把這個Nio的Channel和它的準備狀態傳給父類構造器,而後父類構造器裏存儲到成員變量中。下面無恥的貼點源碼。socket
public NioServerSocketChannel() { this(newSocket(DEFAULT_SELECTOR_PROVIDER)); } //這個DEFAULT_SELECTOR_PROVIDER其實就是select的provide private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider(); //而後是newSocket打開了一個Channel private static ServerSocketChannel newSocket(SelectorProvider provider) { try { return provider.openServerSocketChannel(); } catch (IOException e) { throw new ChannelException( "Failed to open a server socket.", e); } } //最後是調用父類的構造 public NioServerSocketChannel(ServerSocketChannel channel) { super(null, channel, SelectionKey.OP_ACCEPT); config = new NioServerSocketChannelConfig(this, javaChannel().socket()); }
看到這些,我想你們對Channel有所瞭解了吧,如今咱們來開始實現本身的版本ide
在這以前先說下bootstrap的bind方法,這邊netty實現的比較複雜,它是經過各類線程異步,還有它的一個內部類unsafe,最後調用到NioServerSocketChannel的doBind方法,doBind在調用Java Nio的bind方法。這裏咱們先實現簡單版本,它的關於線程的一些設計,咱們說到eventloop以後再說。oop
先來實現Channel和Channel工廠類,方便咱們動態new出不一樣的Channel。測試
public interface Channel { void bind(InetSocketAddress inetSocketAddress); } public interface ChannelFactory<T extends Channel>{ T newChannel(); } public class ReflectChannelFactory<T extends Channel> implements ChannelFactory<T> { private final Class<? extends T> clazz; public ReflectChannelFactory(Class clazz) { this.clazz = clazz; } public T newChannel() { try { return clazz.newInstance(); } catch (Exception e) { throw new IllegalArgumentException("can not init"); } } }
咱們也學netty,把啓動類抽象成兩層,方便之後寫客戶端。
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B,C>,C extends Channel> { private ChannelFactory<C> channelFactory; public B channel(Class<? extends C> clazz){ this.channelFactory = new ReflectChannelFactory<C>(clazz); return (B)this; } public B bind(Integer port){ validate(); doBind(port); return (B)this; } private void doBind(Integer port){ Channel channel = channelFactory.newChannel(); channel.bind(new InetSocketAddress(port)); } public void validate(){ if(channelFactory == null){ throw new IllegalArgumentException("channelFactory should be initialized"); } } } //服務端暫時沒有用到額外的方法,先直接繼承就OK了 public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap,Channel>{ }
最後咱們實現咱們的NioChannel,相比netty,咱們目前只作了兩層抽象。
public abstract class AbstractNioChannel implements Channel{ private final SelectableChannel ch; public AbstractNioChannel(SelectableChannel ch) { this.ch = ch; } protected SelectableChannel ch() { return ch; } protected abstract void doBind(SocketAddress localAddress) throws Exception; public void bind(InetSocketAddress inetSocketAddress) { try { doBind(inetSocketAddress); } catch (Exception e) { e.printStackTrace(); } } } public class NioServerSocketChannel extends AbstractNioChannel { public NioServerSocketChannel() { super(newSocket()); } private static ServerSocketChannel newSocket(){ try { return SelectorProvider.provider().openServerSocketChannel(); } catch (IOException e) { throw new IllegalArgumentException("can not open socket"); } } @Override protected ServerSocketChannel ch(){ return (ServerSocketChannel) super.ch(); } @Override protected void doBind(SocketAddress localAddress) throws Exception{ ch().socket().bind(localAddress); } }
最後寫個測試類,來測試下
public class Test { public static void main(String[] args) { ServerBootstrap sb = new ServerBootstrap(); sb.channel(NioServerSocketChannel.class).bind(9999); } }
固然,這個連殘缺版netty都算不上,在綁定完端口後就自動結束了。彆着急,咱們慢慢來,下一篇咱們會了解EventLoopGroup以及他的成員EventLoop,而後,完善咱們的程序,增長其接收數據的能力。
文章的源碼我會同步更新到個人gayHub上,歡迎你們star,哈哈。