netty源码走读(服务端Channel创建流程)

Posted 大数据技术圈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了netty源码走读(服务端Channel创建流程)相关的知识,希望对你有一定的参考价值。

概念:

NioEventLoop

Channel:

ByteBuf:

PipeLine:

ChannelHandler:

服务器端启动流程:

创建服务器端`Channel`->初始化服务器端`Channel`->注册`Selector`->端口绑定

创建服务器端Channel从用户代码的bind()方法入口,调用initAndRegister()方法,在initAndRegister()方法中,调用newChannel()方法,创建服务器端Channel.
ChannelFuture future = bootstrap.bind(8090).sync(); 

整个调用过程逻辑相对比较清晰。

    final ChannelFuture initAndRegister() {
       Channel channel = null;        
       try {
           channel = channelFactory.newChannel();
           init(channel);
       } catch (Throwable t) {

我们跟进newChannel()方法,看一下Channel的创建过程.

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

Channel的创建是以反射的方式创建。那我们就看一下clazz对应的实例是谁,从而也就知道了反射后创建的Channel的具体类型了。

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {    
   private final Class<? extends T> clazz;    
   public ReflectiveChannelFactory(Class<? extends T> clazz) {        
       if (clazz == null) {            
           throw new NullPointerException("clazz");
       }        
       this.clazz = clazz;
   }

clazz是从外部接收的一个Class实例。既然是外部接收的,就看一下我们的Server端代码

bootstrap.group(master,worker)                
       .channel(NioserverSocketChannel.class)

我们跟进channel()方法

    public B channel(Class<? extends C> channelClass) {        
       if (channelClass == null) {            
           throw new NullPointerException("channelClass");
       }      
       return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
   }

  我们传进去的channelClass也就是NioServerSocketChannel.class,交给了ReflectiveChannelFactory。这样就知道了我们服务端创建的是NioServerSocketChannel。我们跟进NioServerSocketChannel类,看一下这个类的实例化过程。

  由于在利用反射创建NioServerSocketChannel时候,channel = channelFactory.newChannel();没有传参进去,我们需要跟进NioServerSocketChannel的无参构造函数。

    public NioServerSocketChannel() {        
       this(newSocket(DEFAULT_SELECTOR_PROVIDER));
   }

跟进this构造函数

    public NioServerSocketChannel(ServerSocketChannel channel) {        
       super(null, channel, SelectionKey.OP_ACCEPT);
       config = new NioServerSocketChannelConfig(this, javaChannel().socket());
   }

抽丝剥茧,跟进newSocket()方法,并将newSocket的返回值ServerSocketChannel作为参数传递给NioServerSocketChannel(ServerSocketChannel channel)

    private static ServerSocketChannel newSocket(SelectorProvider provider) {        
   try {  
           return provider.openServerSocketChannel();
       } catch (IOException e) {            
           throw new ChannelException("Failed to open a server socket.", e);
       }
   }

newSocket中,nettyjdk底层Socket建立了连接。

在初始化NioServerSocketChannel时,创建了NioServerSocketChannelConfig,主要负责给创建的jdk底层的Socket的TCP相关配置。

我们跟进

public NioServerSocketChannel(ServerSocketChannel channel) {        
   super(null, channel, SelectionKey.OP_ACCEPT);

进入父类的构造函数

    protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {        
       super(parent, ch, readInterestOp);
   }

继续跟进

    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {        
       super(parent);        
       this.ch = ch;        
       this.readInterestOp = readInterestOp;        
   try {
           ch.configureBlocking(false);
       } catch (IOException e) {

当我们看到ch.configureBlocking(false)这行代码的时候,就知道了创建出来的Socket是非阻塞模式。

继续跟进父类

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

创建了Channel的唯一标识id,unsafe封装了Channel和底层相关的操作,pipeline封装了跟服务端程序相关的逻辑链。至此服务端NioServerSocketChannel创建成功。



以上是关于netty源码走读(服务端Channel创建流程)的主要内容,如果未能解决你的问题,请参考以下文章

Netty源码分析之处理新连接

浅谈Netty中ServerBootstrap服务端源码(含bind全流程)

3-2 服务端Channel的创建

netty源码之启动流程

netty源码之启动流程

Netty源码分析-AbstractUnsafe(register注册流程)