2.Netty源码分析二(Channel)

从Bootstrap入手,在服务端和客户端启动过程中都需要使用到channel()方法,以下是channel()方法源码

//AbstractBootstrap
public B channel(Class<? extends C> channelClass) {  
    return channelFactory(new ReflectiveChannelFactory<C>(  
            ObjectUtil.checkNotNull(channelClass, "channelClass")  
    ));  
}

可以看到,以上代码使用了channelFactory()方法,并传入了ReflectiveChannelFactory的实例

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {  
  
    private final Constructor<? extends T> constructor;  
  
    public ReflectiveChannelFactory(Class<? extends T> clazz) {  
        ObjectUtil.checkNotNull(clazz, "clazz");  
        try {  
            this.constructor = clazz.getConstructor();  
        } catch (NoSuchMethodException e) {  
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +  
                    " does not have a public non-arg constructor", e);  
        }  
    }  
	//该方法是该类中唯一的方法,使用反射直接获取到channel的实例
    @Override  
    public T newChannel() {  
        try {  
            return constructor.newInstance();  
        } catch (Throwable t) {  
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);  
        }  
    }  
  
    @Override  
    public String toString() {  
        return StringUtil.simpleClassName(ReflectiveChannelFactory.class) +  
                '(' + StringUtil.simpleClassName(constructor.getDeclaringClass()) + ".class)";  
    }  
}

对于io.netty.channel.ReflectiveChannelFactory#newChannel方法,使用了工厂模式➕反射机制,通过无参构造函数实例化channel

public ChannelFuture connect(InetAddress inetHost, int inetPort) {  
    return connect(new InetSocketAddress(inetHost, inetPort));  
}  
  
public ChannelFuture connect(SocketAddress remoteAddress) {  
	//非空校验
    ObjectUtil.checkNotNull(remoteAddress, "remoteAddress");
    //校验channelFactory是否存在,以及其他参数是否正确配置  
    validate();  
    return doResolveAndConnect(remoteAddress, config.localAddress());  
}

继续阅读doResolveAndConnect(..)方法

private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {  
    final ChannelFuture regFuture = initAndRegister();  
    final Channel channel = regFuture.channel();  
	....  
}

AbstractBootstrap中的initAndRegister方法就会帮助我们初始化channel,当然,其中的init()方法由对应子类(Bootstrap和ServerBootstrap)分别实现。

final ChannelFuture initAndRegister() {  
    Channel channel = null;  
    try {  
        channel = channelFactory.newChannel();  
        init(channel);  
    } catch (Throwable t) {  
        if (channel != null) {  
            // channel can be null if newChannel crashed (eg SocketException("too many open files"))  
            channel.unsafe().closeForcibly();  
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor  
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);  
        }  
        // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor  
        return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);  
    }  
  
    ChannelFuture regFuture = config().group().register(channel);  
    if (regFuture.cause() != null) {  
        if (channel.isRegistered()) {  
            channel.close();  
        } else {  
            channel.unsafe().closeForcibly();  
        }  
    }  
    return regFuture;  
}

根据之前EchoClient可以知道,此时的channel应该是NioSocketChannel,所以此时就需要看下NioSocketChannel的构造方法

private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();

public NioSocketChannel() {  
    this(DEFAULT_SELECTOR_PROVIDER);  
}

public NioSocketChannel(SelectorProvider provider) {  
    this(provider, null);  
}

//该构造方法是最终执行的构造方法,可以看到调用了newChannel方法
public NioSocketChannel(SelectorProvider provider, InternetProtocolFamily family) {  
    this(newChannel(provider, family));  
}

newChannel(..)方法,最终生产出的SocketChannel就是JDK NIO 的SocketChannel实例

private static SocketChannel newChannel(SelectorProvider provider, InternetProtocolFamily family) {  
    try {  
        SocketChannel channel = SelectorProviderUtil.newChannel(OPEN_SOCKET_CHANNEL_WITH_FAMILY, provider, family);  
        return channel == null ? provider.openSocketChannel() : channel;  
    } catch (IOException e) {  
        throw new ChannelException("Failed to open a socket.", e);  
    }  
}

ServerBootstrap同理,最终会生产JDK NIO ServerScoketChannel实例。

可以继续看下NioSocketChannel的构造方法

public NioSocketChannel(Channel parent, SocketChannel socket) {  
    super(parent, socket);  
    config = new NioSocketChannelConfig(this, socket.socket());  
}

第一行super调用父类构造器

protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {  
    //客户端只关注OP_READ事件,等待读取服务端返回数据
    super(parent, ch, SelectionKey.OP_READ);  
}

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {  
    super(parent);  
    this.ch = ch;  
    //保存SelectionKey.OP_READ
    this.readInterestOp = readInterestOp;  
    try {  
	    //设置channel为非阻塞模式
        ch.configureBlocking(false);  
    } catch (IOException e) {  
        try {  
            ch.close();  
        } catch (IOException e2) {  
            logger.warn(  
                        "Failed to close a partially initialized socket.", e2);  
        }  
  
        throw new ChannelException("Failed to enter non-blocking mode.", e);  
    }  
}

NioServerSocketChannel类似,与客户端区别在于服务端关注SelectionKey.OP_ACCEPT事件

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

对于Netty的channel来说,主要目的就是实例华JDK的channel实例,然后设置非阻塞模式