1 引入netty的maven依赖如下



<dependency>
   
 
   

        <groupId>io.netty</groupId>
   
 
   

        <artifactId>netty-all</artifactId>
   
 
   

        <version>4.1.6.Final</version>
   
 
   

    </dependency>


2 netty的基本组件如下



 



Netty源码简析之服务端Channel的创建_赋值

 



  • Channel:Java Stream是以流的方式一个一个byte通过滑动窗口来接收,是连续性的,造成阻塞,只能一次性接收完。而NIO Channel非阻塞,但是必须通过Buffer来中转。
  • Buffer:可理解为一个数组的封装,例如 IntBuffer、CharBuffer、ByteBuffer 等分别对应 int[]、char[]、byte[] 等。有Byte/Short/Long/Int/Float/Double/Char/MappedByteBuffer。
  • buffer四个基本属性:
  • capacity:当前buffer的最大容量,如int[] buffer = new int[1024];  那capacity=1024 
  • position:当前buffer真实已用的下一个位置,如buffer最大容量=1024,现在真实用了500,那position=500
  • limit:读情况下,limit=buffer实际大小;写情况下,limit=capacity
  • mark:记录当前postion位置,即标记上一次读写位置
  • mark <= position <= limit <= capacity
  • Selector:轮询channel,轮询到某个channel是读写时间的就绪状态,就取出来

netty启动过程分为:



- 创建服务端channel



- 初始化服务端channel



- 注册selector



 



3 以下是一个简单的netty服务段程序代码(在后续部分讲解会用到)



public static void main(String[] args) throws Exception {
   
 
   

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
   
 
   

        EventLoopGroup workerGroup = new NioEventLoopGroup();
   
 
   

     
   
 
   

        try {
   
 
   

            ServerBootstrap b = new ServerBootstrap();
   
 
   

            b.group(bossGroup, workerGroup)
   
 
   
A点
 
   

                    .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();
   
 
   

        }
   
 
   

    }


4 服务端Channel的创建过程


/** AbstractBootStrap.java类中
  
 
  

   * Create a new {@link Channel} and bind it.
  
 
  

   */
  
 
  
public ChannelFuture bind(int inetPort) {
 
  
    return bind(new InetSocketAddress(inetPort));
 
  
}
 
  

    
  
 
  

   /** AbstractBootStrap.java类中
  
 
  

   * Create a new {@link Channel} and bind it.
  
 
  

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

   然后调用initAndRegister()创建服务端channel
  
 
  
// AbstractBootStrap.java类中
  
 
  
private ChannelFuture doBind(final SocketAddress localAddress) {
 
  
    final initAndRegister();
 
  
    final Channel channel = regFuture.channel();
 
  
    ...........
 
  
}
 
  

   最终发现是通过newChannel()创建的,点进去发现是由clazz.newInstance()反射来创建一个channel
  
 
  
final ChannelFuture initAndRegister() {
 
  
    Channel channel = null;
 
  
    try {
 
  
        channel = channelFactory.newChannel();
 
  
        init(channel);
 
  
        ...................
 
  
}

阅读上面的代码可知channel是通过反射来创建的,但是对应的对象channelFactory是如何初始化的?



首先我们看3的A点,可以看到通过.chanel(NioServerSocketChannel.class)设置了channelFactory,往下继续跟



 



Netty源码简析之服务端Channel的创建_channel_02

 



点击.channel()方法后进入查看如下



public B channel(Class<? extends C> channelClass) {
  
 
  

       ...........
  
 
  
    return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
 
  

   }
  
 
  

   上面可知 NioServerSocketChannel.class 传入ReflectiveChannelFactory中,然后赋值给了里面的一个clazz参数。然后最后包装好会赋值给AbstractBootStrap.java的channelFactory属性,最终复制代码如下
  
 
  
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
  
 
  
if (channelFactory == null) {
  
 
  
throw new NullPointerException("channelFactory");
 
  

   }
  
 
  
if (this.channelFactory != null) {
  
 
  
throw new IllegalStateException("channelFactory set already");
 
  

   }
  
 
  

    
  
 
  
this.channelFactory = channelFactory;
 
  
return (B) this;
 
  

   }
  
 
  
总结:通过channel(NioServerSocketChannel.class),传入NioServerSocketChannel.class,然后使用ReflectiveChannelFactory包装后赋值给channelFactory属性。然后最终调用clazz.newInstance()来实例化一个channel实例。
  
 
  

    
  
 
  

   通过上面我们可以知道channel是通过反射来创建的,接下来我们来看看他创建对应的NioServerSocketChannel.java类,其构造方法如下:
  
 
  
public NioServerSocketChannel() {
  
 
  
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
 
  

   }
  
 
  

   首先点击newSocket()方法如下,可见调用的jdk底层来创建socket(点击openServerSocketChannel() 可见其在jdk1.8的包中)
  
 
  
private static ServerSocketChannel newSocket(SelectorProvider provider) {
  
 
  
    try
 
  
        return provider.openServerSocketChannel();
 
  
catch
 
  
        throw new ChannelException("Failed to open a server socket.", e);
 
  

       }
  
 
  

   }
  
 
  

   然后继续点击this(newSocket(DEFAULT_SELECTOR_PROVIDER))的this,找到当前对应的方法如下:
  
 
  
public NioServerSocketChannel(ServerSocketChannel channel) {
  
 
  
    super(null, channel, SelectionKey.OP_ACCEPT);
 
  
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
 
  

   }
  
 
  

   点击super()层层往上看,最后找到代码如下:
  
 
  
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int
 
  
    super(parent);
 
  
    this.ch = ch;
 
  
    this.readInterestOp = readInterestOp;
 
  
    try
 
  
        ch.configureBlocking(false);   //设置非阻塞
 
  

       .................
  
 
  

   }
  
 
  

   由上可见其默认设置了非阻塞(通过 ch.configureBlocking(false)  设置),继续看上面的super(parent)方法如下:
  
 
  
protected AbstractChannel(Channel parent) {
  
 
  
    this.parent = parent;
 
  
    id = newId();
 
  
    unsafe = newUnsafe();
 
  
    pipeline = newChannelPipeline();
 
  

   }



可看到其最终赋值了(id,unsafe,pipeline)这三个属性,这几个属性将会在后续用到。