在普通IO
中,通过把机器传输抽象成java.net.Socket
流,也就是Socket
和ServerSocket
到NIO
时,则变为了java.nio.channels.Channel
,也是作为传输的管道,具体可看Java Netty 学习(四) - NIO基础知识Channel和Pipe
那今天就一起学习Netty中的Channel,看它又是一种怎么样的设计形式。
在netty的Channel中,提供了很多共用的API,相比与大大降低了直接使用Socket
的复杂性。另外,它是Netty网络通信的主题,由他负责直接对端进行网络通信,注册,以及相关的数据操作。
Channel提供了许多预定义的专门实现的类:
Channel接口里面主要有以下方法:
按照Channel定义的模型,Channel有四个状态
记得上一篇文章给出的实例,Bootstrap调用的建造者模式的过程中用到了NioSocketChannel
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new HelloClientHandler());
}
});
下面跟着源码看看里面做了些什么事:
public B channel(Class channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory(channelClass));
}
再看channelFactory:
public B channelFactory(io.netty.channel.ChannelFactory channelFactory) {
return channelFactory((ChannelFactory) channelFactory);
}
最后设置以下channelFactory:
public B channelFactory(ChannelFactory 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方法里面,首先还是返回一个AbstractBootstrap
的子类以供继续建造对象,接着把一个
ReflectiveChannelFactory
对象传递给了channelFactory
,并且以传入的channelClass为参数,名字上可知是返回一个channel类,包装了很多层工厂方法为了实现代码的统一性。
进入源码可知,ReflectiveChannelFactory
是一个继承了ChannelFactory
的对象里面有一个newChannel
方法如下:
@Override
public T newChannel() {
try {
return clazz.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + clazz, t);
}
}
执行了传入参数的Class的newInstance
方法。
现在已经清楚知道Bootstrap中的channel方法做了什么事了,就是把一个相应类型的ChannelFactory传进去,这样就可以产生Channel。
那么,NioSocketChannel什么时候被初始化的呢?
首先在NioSocketChannel中打断点,跟踪到调用服务:
可以很清楚的看到
由connect->doResolveAndConnect->initAndRegister->newChannel一级一级调用:
返回一个异步的ChannelFuture
ChannelFuture future = b.connect(this.address, this.port);
再到:
public ChannelFuture connect(String inetHost, int inetPort) {
return connect(InetSocketAddress.createUnresolved(inetHost, inetPort));
}
接着在doResolveAndConnect
执行初始化一个Channel,但此时并没有连接上,就相当先拿到一个默认配置的Channel,但是现在还没有用。
接着执行initAndRegister
,并在这里面调用:
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
} catch (Throwable t) {
if (channel != null) {
channel.unsafe().closeForcibly();
}
return new DefaultChannelPromise(channel, 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;
}
从而再经过JNI等一步步反射调用NioSocketChannel的构造方法。
public NioSocketChannel() {
this(DEFAULT_SELECTOR_PROVIDER);
}
那么,Channel创建了,也初始化了,那么它在Netty里面,地位是啥呢?
先看看一张图:
上图有以下几个概念:
并且,多个Channel可以同时注册到同一个EventLoop,并按照顺序循环处理Channel中的逻辑。
Channel就类似于一个容器,或者理解为Socket,通过它与另一端进行通信,由EventLoop来处理Channel中产生的事件,在事件中实现相关逻辑,接下来文章将逐步学习其他组件。
帮助: