同步异步是相对于IO而言的,在同一时间,只能完成一个操作,则为同步(NIO);能同时完成多个操作,则为异步(AIO)。
阻塞非阻塞是相对于数据而言的,判断数据有没有准备好,如果数据没有准备好,则一直等待,则为阻塞(BIO);如果不管数据有没有准备好,都会给一个反馈,客户端可以去做一些其他事情,则为非阻塞。
简单来说,同步异步针对于底层操作系统的IO操作,阻塞非阻塞针对于接口的调用
而Netty是基于NIO的异步非阻塞,异步的原因是加了一个线程池,在同一时间,就能同时完成多个操作,拥有了异步响应;
异步响应是从Handler来体现的,这些Handler组成了Pipeline,即一条无锁化串行的链路
其使用链为
EventLoopGroup workerGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap .group(workerGroup);
.channel(NioSocketChannel.class);
.option(ChannelOption.SO_KEEPALIVE, true);
.handler(new ChannelInitializer() {
。。。
});
ChannelFuture f = b.connect(this.host, this.port).sync();
f.channel().closeFuture().sync();
客户端:Bootstrap;服务端:ServerBootstrap
首先分析一下Channel的初始化过程:
ChannelFactory负责初始化实现了Channel接口的类,不同协议、不同阻塞类型的连接都有不同的Channel类型与之对应,下图是一些常用的Channel类型:
因为是讲客户端,所以这里看一下NioSocketChannel,其类层次结构图如下:
注意到,NioSocketChannel是Nio客户端的起始类
这里以NioSocketChannel为例,来查看源码:
AbstractBootstrap#
public B channel(Class<? extends C> channelClass) {
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));*
}
ReflectiveChannelFactory#
public ReflectiveChannelFactory(Class<? extends T> clazz) {
this.clazz = clazz;
}
public T newChannel() {
return clazz.newInstance();
}
可以看到,这里初始化了ReflectiveChannelFactory,而ReflectiveChannelFactory实现了ChannelFactory接口,将class保存下来,进行newInstance。即将new的权利交给了框架,类似IOC
那么什么时候调用newChannel呢?调用链如下:
final ChannelFuture initAndRegister() {
channel = channelFactory.newChannel();
}
因此可以看到,connect是实例化channel必备的代码
使用class的newInstance,会调用类的构造方法,即NioSocketChannel的默认构造方法:
public NioSocketChannel() {
//DEFAULT_SELECTOR_PROVIDER为Nio的provider,= SelectorProvider.provider()
//即不同操作系统的IO多路复用器:https://www.jianshu.com/p/3cf951d46c35
this(DEFAULT_SELECTOR_PROVIDER);
}
public NioSocketChannel(SelectorProvider provider) {
this(newSocket(provider));//return provider.openSocketChannel();即获取SocketChannel
}
public NioSocketChannel(SocketChannel socket) {
this(null, socket);
}
public NioSocketChannel(Channel parent, SocketChannel socket) {
super(parent, socket);//ch.configureBlocking(false);
config = new NioSocketChannelConfig(this, socket.socket());
}
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();//模板模式,由子类实现
pipeline = newChannelPipeline();//new DefaultChannelPipeline(this);
}
下面可以来看看组合进Channel的pipeline和unsafe:
1.pipeline:实例化Channel过程中,也实例化了ChannelPipeline
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
//头尾相连,next和prev由volatile修饰
head.next = tail;
tail.prev = head;
}
可以看到,其本质就是一个链表,体现了能够进行串行化的原因
接下来看看孪生兄弟HeadContext和TailContext:
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler{
//即令inbound = false;outbound = true;
super(pipeline, null, HEAD_NAME, false, true);
}
final class TailContext extends AbstractChannelHandlerContext
implements ChannelInboundHandler{
//即令inbound = true;outbound = false;
super(pipeline, null, TAIL_NAME, true, false);
}
所以header是一个outboundHandler,tail是一个inboundHandler,header比tail多实现了一个ChannelOutboundHandler接口
2.unsafe:封装了对Java底层Socket的操作,是沟通Netty上层和Java底层重要的桥梁
protected class NioByteUnsafe extends AbstractNioUnsafe {}
protected abstract class AbstractNioUnsafe extends AbstractUnsafe implements NioUnsafe{}
public interface NioUnsafe extends Unsafe{}
interface Unsafe{}
可以看到,最深层的接口为Unsafe:
interface Unsafe {
RecvByteBufAllocator.Handle recvBufAllocHandle();
SocketAddress localAddress();
SocketAddress remoteAddress();
void register(EventLoop eventLoop, ChannelPromise promise);
void bind(SocketAddress localAddress, ChannelPromise promise);
void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
void disconnect(ChannelPromise promise);
void close(ChannelPromise promise);
void closeForcibly();
void deregister(ChannelPromise promise);
void beginRead();
void write(Object msg, ChannelPromise promise);
void flush();
ChannelPromise voidPromise();
ChannelOutboundBuffer outboundBuffer();
}
可以看到,无非是一些注册、绑定、关闭、连接、半开连接之类的底层操作,这些方法都会有相关的Java底层的Socket操作
channel初始化之后,来分析一下channel的注册:
回顾刚才的initAndRegister方法,里面调用了init(channel):
void init(Channel channel) throws Exception {
ChannelPipeline p = channel.pipeline();
p.addLast(config.handler());
}
可以看到在pipeline中加入了一个config.handler,这个handler实际上就是在使用代码中的ChannelInitializer,ChannelInitializer,它有一个抽象方法initChannnel方法,用来addLast
AbstractChannel$AbstractUnsafe#register()
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
AbstractChannel.this.eventLoop = eventLoop;
register0(promise);
}
register0:
protected void doRegister() throws Exception {
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
}
可以看到,往Selector中注册一个事件,这个事件就是上面所说的OP_READ;然后返回一个Nio的SocketChannel,这个SocketChannel是已经注册到与eventLoop关联的selector上了