Bootstrap运行原理分析
NioSocketChannel初始化
(1)调用NioSocketChannel.newSocket(DEFAULT_SELECTOR_PROVIDER)打开一个新的JavaNioSocketChannel。
(2)初始化AbstractChannel(Channel parent)对象并给属性赋值,具体赋值的属性如下。
● id:每个Channel都会被分配一个唯一的id。
● parent:属性值默认为null。
● unsafe:通过调用newUnsafe()方法实例化一个Unsafe对象,它的类型是AbstractNioByteChannel.NioByteUnsafe内部类。
● pipeline:是通过调用new DefaultChannelPipeline(this)新创建的实例。
(3)AbstractNIOChannel中被赋值的属性如下。
● ch:被赋值为Java原生SocketChannel,即NioSocketChannel的newSocket()方法返回的Java NIO SocketChannel。
● readInterestOp:被赋值为SelectionKey.OP_READ。
● ch:被配置为非阻塞,即调用ch.configureBlocking(false)方法。
(4)NioSocketChannel中被赋值的属性:config=new NioSocketChannelConfig(this,socket.socket())。
Unsafe初始化
Unsafe其实是对Java底层Socket操作的封装,它实际上是沟通Netty上层和Java底层的重要桥梁。
在实例化的NioSocketChannel中的Unsafe属性其实是一个NioSocketChannelUnsafe的实例。
//AbstractChannel.java
//构造函数
protected AbstractChannel(Channel parent) {
this.parent = parent;
unsafe = newUnsafe();
pipeline = new DefaultChannelPipeline(this);
}
protected abstract AbstractUnsafe newUnsafe();
//NioSocketChannel.java
protected AbstractNioUnsafe newUnsafe() {
return new NioSocketChannelUnsafe();
}
ChannelPipeline的初始化
//NioSocketChannel或者NioServerSocketChannel#的多级父类中AbstractChannel中初始化Channel时,实例化了一个ChannelPipeline
protected AbstractChannel(Channel parent) {
this.parent = parent;
unsafe = newUnsafe();
pipeline = new DefaultChannelPipeline(this);
}
在实例化一个Channel时,必然都要实例化一个ChannelPipeline。而我们确实在AbstractChannel的构造器中看到了Pipeline属性被初始化为DefaultChannelPipeline的实例
//DefaultChannelPipeline的构造器需要传入一个Channel,而这个Channel其实就是我们实例化的NioSocketChannel对象
public DefaultChannelPipeline(AbstractChannel channel) {
if (channel == null) {
throw new NullPointerException("channel");
}
// DefaultChannelPipeline会将这个NioSocketChannel对象保存在Channel属性中
this.channel = channel;
//这两个属性是双向链表的头和尾。其实在DefaultChannelPipeline中维护了一个以AbstractChannelHandlerContext为节点元素的双向链表,这个链表是Netty实现Pipeline机制的关键
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
链表中Head是一个ChannelOutboundHandler,而Tail则是一个ChannelInboundHandler
//一个特殊的包罗万象的处理程序,可以处理字节和消息。
//TailContext
static final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
}
//HeadContext
static final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler {
}
EventLoop的初始化
public class NioEventLoopGroup extends MultithreadEventLoopGroup {
//Netty首先从系统属性中获取“io.netty.eventLoopThreads”的值,如果我们没有设置,就返回默认值,即CPU核数×2
public NioEventLoopGroup(int nThreads) {
this(nThreads, null);
}
}
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
}
public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
//创建一个大小为nThreads的SingleThreadEventExecutor数组。
private final EventExecutor[] children;
private final AtomicInteger childIndex = new AtomicInteger();
private final AtomicInteger terminatedChildren = new AtomicInteger();
private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
private final EventExecutorChooser chooser;
}
MultithreadEventExecutorGroup处理逻辑
(1)创建一个大小为nThreads的SingleThreadEventExecutor数组。
(2)根据nThreads的大小,创建不同的Chooser,即如果nThreads是2的平方,则使用PowerOfTwoEventExecutorChooser,反之使用GenericEventExecutorChooser。不论使用哪个Chooser,它们的功能都是一样的,即从children数组中选出一个合适的EventExecutor实例。
(3)调用newChild()方法初始化children数组。
EventLoopGroup的初始化过程
(1)EventLoopGroup(其实是MultithreadEventExecutorGroup)内部维护一个类型为EventExecutor的children数组,其大小是nThreads,这样就构成了一个线程池。
(2)我们在实例化NioEventLoopGroup时,如果指定线程池大小,则nThreads就是指定的值,反之是CPU核数×2。
(3)在MultithreadEventExecutorGroup中调用newChild()象方法来初始化children数组。
(4)newChild()方法是在NioEventLoopGroup中实现的,它返回一个NioEventLoop实例。
(5)初始化NioEventLoop对象并给属性赋值,具体赋值的属性如下。
● provider:就是在NioEventLoopGroup构造器中,调用SelectorProvider.provider()方法获取的SelectorProvider对象。
● selector:就是在NioEventLoop构造器中,调用provider.openSelector()方法获取的Selector对象。
将Channel注册到Selector
ChannelFuture regFuture = initAndRegister();
ChannelFuture initAndRegister() {
Channel channel = channelFactory().newChannel();
ChannelFuture regFuture = group().register(channel);
return regFuture;
}
AbstractBootstrap的initAndRegister()方法中调用的是Unsafe的register()方法,接下来看一下AbstractChannel$AbstractUnsafe.register()方法的具体实现代码
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
AbstractChannel.this.eventLoop = eventLoop;
this.register0(promise);
}
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !this.ensureOpen(promise)) {
return;
}
boolean firstRegistration = this.neverRegistered;
//register0()方法又调用了AbstractNioChannel的doRegister()方法
AbstractChannel.this.doRegister();
this.neverRegistered = false;
AbstractChannel.this.registered = true;
this.safeSetSuccess(promise);
//Channel已注册到EventLoop
AbstractChannel.this.pipeline.fireChannelRegistered();
if (firstRegistration && AbstractChannel.this.isActive()) {
//现在处于活动状态,表示已连接
AbstractChannel.this.pipeline.fireChannelActive();
}
} catch (Throwable var3) {
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var3);
}
}
public abstract class AbstractNioChannel extends AbstractChannel {
@Override
protected void doRegister() throws Exception {
//这里我们将SocketChannel注册到与eventLoop关联的Selector上
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
}
}
Channel的注册过程
(1)在AbstractBootstrap的initAndRegister()方法中,通过group().register(channel)调用MultithreadEventLoopGroup的register()方法。
(2)在MultithreadEventLoopGroup的register()方法中,调用next()方法获取一个可用的SingleThreadEventLoop,然后调用它的register()方法。
(3)在SingleThreadEventLoop的register()方法中,调用channel.unsafe().register(this,promise)方法获取Channel的unsafe()底层操作对象,然后调用Unsafe的register()方法。
(4)在AbstractUnsafe的register()方法中,调用register0()方法注册Channel对象。
(5)在AbstractUnsafe的register0()方法中,调用AbstractNioChannel的doRegister()方法。
(6)AbstractNioChannel的doRegister()方法通过javaChannel().register(eventLoop().selector,0,this)将Channel对应的Java NIO的SocketChannel注册到一个eventLoop的Selector中,并且将当前Channel作为Attachment与SocketChannel关联。
Handler的添加过程
Netty有一个强大和灵活之处就是基于Pipeline的自定义Handler机制
bootstrap.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(HOST, PORT)
//传入的参数是一个派生于抽象类ChannelInitializer的匿名类,它也实现了ChannelHandler接口
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);
}
});
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
//在channelRegistered()方法中,会调用initChannel()方法,将自定义的Handler添加到ChannelPipeline中
initChannel((C) ctx.channel());
//将自己从ChannelPipeline中删除
ctx.pipeline().remove(this);
ctx.fireChannelRegistered();
}
}
客户端发起连接请求
public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
private ChannelFuture doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
final ChannelPromise promise = channel.newPromise();
if (regFuture.isDone()) {
doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
} else {
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
}
});
}
return promise;
}
private static void doConnect0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
channel.eventLoop().execute(new Runnable() {
......
// eventLoop线程会调用Channel的connect()方法
channel.connect(remoteAddress, localAddress, promise);
......
});
}
}
继续跟踪channel.connect()方法,我们发现它调用的是DefaultChannelPipeline的connect()方法
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return pipeline.connect(remoteAddress, promise);
}
}
Tail是一个TailContext的实例,而TailContext又是AbstractChannelHandlerContext的子类,并且没有实现connect()方法,因此这里调用的其实是AbstractChannelHandlerContext的connect()方法
final class DefaultChannelPipeline implements ChannelPipeline {
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return tail.connect(remoteAddress, promise);
}
}
@Override
public ChannelFuture connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
if (remoteAddress == null) {
throw new NullPointerException("remoteAddress");
}
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
//从DefaultChannelPipeline内的双向链表的Tail开始,不断向前找到第一个Outbound为true的AbstractChannelHandlerContext,
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
// 然后调用它的invokeConnect()方法
next.invokeConnect(remoteAddress, localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeConnect(remoteAddress, localAddress, promise);
}
}, promise, null);
}
return promise;
}
private AbstractChannelHandlerContext findContextOutbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}
private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
if (invokeHandler()) {
try {
//这里调用的是ChannelOutboundHandler的connect ,实际调用的是DefaultChannelPipeline的connect
((ChannelOutboundHandler) handler()).connect(this, remoteAddress, localAddress, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
} else {
connect(remoteAddress, localAddress, promise);
}
}
final class DefaultChannelPipeline implements ChannelPipeline {
@Override
public void connect(
ChannelHandlerContext ctx,
SocketAddress remoteAddress, SocketAddress localAddress,
ChannelPromise promise) throws Exception {
//调用AbstractNioChannel的connect方法
unsafe.connect(remoteAddress, localAddress, promise);
}
}
public abstract class AbstractNioChannel extends AbstractChannel {
public final void connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
......
//doConnect()方法是在NioSocketChannel中实现的,因此进入NioSocketChannel的doConnect()方法
if (doConnect(remoteAddress, localAddress)) {
fulfillConnectPromise(promise, wasActive);
} else {
......
}
}
public class NioSocketChannel extends AbstractNioByteChannel implements io.netty.channel.socket.SocketChannel {
@Override
protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
if (localAddress != null) {
javaChannel().socket().bind(localAddress);
}
boolean success = false;
try {
//获取Java NIO的SocketChannel,然后获取NioSocketChannel的newSocket()方法返回的SocketChannel对象;再调用SocketChannel的connect()方法完成Java NIO底层的Socket连接
boolean connected = javaChannel().connect(remoteAddress);
if (!connected) {
selectionKey().interestOps(SelectionKey.OP_CONNECT);
}
success = true;
return connected;
} finally {
if (!success) {
doClose();
}
}
}
}