netty 的服务端启动源码解析

38 阅读2分钟

源码解析

 EventLoopGroup bossGroup = new NioEventLoopGroup(1);
         EventLoopGroup workerGroup = new NioEventLoopGroup();
 ​
         try {
             ServerBootstrap b = new ServerBootstrap();
             b.group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel.class)
                     .childOption(ChannelOption.TCP_NODELAY, true)
                     .childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")
                     .handler(new ServerHandler())
                     .childHandler(new ChannelInitializer<SocketChannel>() {
                         @Override
                         public void initChannel(SocketChannel ch) {
                             ch.pipeline().addLast(new AuthHandler());
                             //..
 ​
                         }
                     });
 ​
             ChannelFuture f = b.bind(8888).sync();
 ​
             f.channel().closeFuture().sync();
         } finally {
             bossGroup.shutdownGracefully();
             workerGroup.shutdownGracefully();
         }

首先从bind入手解析,进入bind()

 public ChannelFuture bind(SocketAddress localAddress) {
         validate();
         if (localAddress == null) {
             throw new NullPointerException("localAddress");
         }
         return doBind(localAddress);
     }

进入doBind(),进入initAndRegister()

 channel = channelFactory.newChannel();
 init(channel);

发现channel是在这里面注册的

进入newChannel()发现是接口,进入他的实现类ReflectiveChannelFactory

发现channel是通过这个方法生成的

 public T newChannel() {
         try {
             return clazz.newInstance();
         } catch (Throwable t) {
             throw new ChannelException("Unable to create Channel from class " + clazz, t);
         }
     }

那clazz是什么东西呢?

我们进入到channel中查看

 b.group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel.class)
 public B channel(Class<? extends C> channelClass) {
         if (channelClass == null) {
             throw new NullPointerException("channelClass");
         }
         return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
     }

发现new ReflectiveChannelFactory(channelClass)将NioServerSocketChannel.class注册到了ReflectiveChannelFactory中

这个类就是刚才注册channel接口的实现类

这是他的构造方法。

 public ReflectiveChannelFactory(Class<? extends T> clazz) {
         if (clazz == null) {
             throw new NullPointerException("clazz");
         }
         this.clazz = clazz;
     }

从以上我们知道了netty中的channel就是我们传入的NioServerSocketChannel.class。

那NioServerSocketChannel这个类是什么呢?

进一步点进去看一看

这是他的构造方法

 //首先通过newSocket(DEFAULT_SELECTOR_PROVIDER)创建一个socket
 public NioServerSocketChannel() {
         this(newSocket(DEFAULT_SELECTOR_PROVIDER));
     }
 ​
 public NioServerSocketChannel(ServerSocketChannel channel) {
         super(null, channel, SelectionKey.OP_ACCEPT);
         config = new NioServerSocketChannelConfig(this, javaChannel().socket());//new 出一个配置类,配置tcp
     }
 ​
 private static ServerSocketChannel newSocket(SelectorProvider provider) {
         try {
             /**
              *  Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
              *  {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
              *
              *  See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.
              */
             return provider.openServerSocketChannel();
         } catch (IOException e) {
             throw new ChannelException(
                     "Failed to open a server socket.", e);
         }
     }

ServerSocketChannel是java.nio中的一个类 是jdk底层的channel

调用父类的构造函数

点进去发现

设置为非阻塞的模式,可以异步的调用connect(), read() write()

 ch.configureBlocking(false);

connect()

如果SocketChannel在非阻塞模式下,此时调用connect(),该方法可能在连接建立之前就返回了。为了确定连接是否建立,可以调用finishConnect()的方法。

write()

非阻塞模式下,write()方法在尚未写出任何内容时可能就返回了。所以需要在循环中调用write()。

read()

非阻塞模式下,read()方法在尚未读取到任何数据时可能就返回了。所以需要关注它的int返回值,它会告诉你读取了多少字节。

调用父类构造函数

配置这个channel

 protected AbstractChannel(Channel parent) {
         this.parent = parent;
         id = newId();
         unsafe = newUnsafe();
         pipeline = newChannelPipeline();
     }