bootStrap家族介绍----3BootStrap初始化--initAndRegister

无论是服务端还是客户端,都会有一步需要调用到父类AbstractBootStrap的initAndRegister()方法,将相应的channel注册到bossReactor线程池中去。

initAndRegister()方法主要分为3个部分:

  • 创建Channel

  • 绑定用户自定义的Handler()

  • 将该Channel注册到Reactor中去

 

final ChannelFuture initAndRegister() {

    Channel channel = null;

 

    try {

        channel = this.channelFactory.newChannel();//创建一个Channel

        this.init(channel);//初始化Handler(),由子类bootstrap或者serverBootStrap进行实现,可视为一个模板方法

    } catch (Throwable var3) {

        if (channel != null) {

            channel.unsafe().closeForcibly();

            return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);

        }

       //还没有注册到线程池。使用默认线程GlobalEventExecutor

        return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3);

    }

    // 将channel注册到Reactor线程池

    ChannelFuture regFuture = this.config().group().register(channel);

    if (regFuture.cause() != null) {

        if (channel.isRegistered()) {

            channel.close();

        } else {

            channel.unsafe().closeForcibly();

        }

    }

 

    return regFuture;

}

 

 

三个步骤一个步骤一个步骤的解析:

1:通过工厂方法创建对应的channel。

     channel = this.channelFactory.newChannel();

看名字就知道是工厂模式产生channel了。在serverBootStrap中是产生一个 NioServerSocketChannel,在bootStrap中是产生一个 NioSocketChannel。具体的生成实例是由channelFactory控制的,而serverBootStrap和bootStrap中的channelFactory类型是不一样的,是在bootstrap或者serverBootStrap的初始化时进行初始化的。如下图,在.channel中,通过传入的参数来控制ChannelFactory的类型。

 

 

=========================================this.channelFactory.newChannel()      ===========================================================

 

channelFactory对象是我们的serverBootStrap.channel初始化的。

public B channel(Class<? extends C> channelClass) {

if (channelClass == null) {

throw new NullPointerException("channelClass");

}

return channelFactory(new ReflectiveChannelFactory<C>(channelClass));

}

此工厂对象是ReflectiveChannelFactory实例

 

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;

}

 

@Override

public T newChannel() {

try {

return clazz.getConstructor().newInstance();

} catch (Throwable t) {

throw new ChannelException("Unable to create Channel from class " + clazz, t);

}

}

}

所以 channelFactory.newChannel() 实例化其实就是NioServerSocketChannel无参构造方法反射而成。

 

====================================this.channelFactory.newChannel() 结束,生成一个NioServerSocketChannel实例==============================================================

 

 

 

 

 

 

=====================  NioServerSocketChannel实例化==================================================================

 

 

以NioServerSocketChannel为例:

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

  • //有两个步骤 1:打开一个默认的多路复用器辅助类 2:新建一个ServerSocketChannel实例

  • public NioServerSocketChannel() {

  •         this(newSocket(DEFAULT_SELECTOR_PROVIDER));

  •     }

  •  

  • private static ServerSocketChannel newSocket(SelectorProvider provider) {

  • try {

  • // 打开一个ServerSocketChannel

  • return provider.openServerSocketChannel();

  • } catch (IOException e) {

  • throw new ChannelException(

  • "Failed to open a server socket.", e);

  • }

  • }

  •  

  • public NioServerSocketChannel(ServerSocketChannel channel) {

  • // 只对OP_ACCEPT事件感兴趣, 因为是服务端新生成的channel,第一个参数指定为null,表示没有父channel,第二个参数指定为ServerSocketChannel,第三个参数指定ServerSocketChannel关心的事件类型为

  • //SelectionKey.OP_ACCEPT。

  •         super(null, channel, 16(SelectionKey.OP_ACCEPT)); //SelectionKey.OP_ACCEPT就是16,就是1往左移4位

  • // 初始化连接对应的配置

  •         config = new NioServerSocketChannelConfig(this, javaChannel().socket());

  •     }

  •  

  •  //上面super调用的父类方法

  • protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {

  •         super(parent);

  • //将serverSocketChannel对象保存

  •         this.ch = ch;

  • //设置关心的事件

  •         this.readInterestOp = readInterestOp;

  •         try {

  • // 将ServerSocketChannel设置为非阻塞模式

  •             ch.configureBlocking(false);

  •         } catch (IOException e) {

  •             try {

  •                 ch.close();

  •             } catch (IOException e2) {

  •                 if (logger.isWarnEnabled()) {

  •                     logger.warn(

  •                             "Failed to close a partially initialized socket.", e2);

  •                 }

  •             }

  •             throw new ChannelException("Failed to enter non-blocking mode.", e);

  •         }

  •     }

 

 

 

 

在AbstractNioChannel中做了下面几件事:

1、继续调用父类AbstractChannel(Channel parent)构造方法;

2、通过this.ch = ch 保存ServerSocketChannel, 因为NioServerSocketChannel是Netty封装的对象,而ServerSocketChannel是有前面默认selector_provider生成的,是java nio的, 其实“this.ch = ch”可以被认为是绑定java nio服务端通道至netty对象中;

3、设置ServerSocketChannel关心的事件类型;

4、设置ServerSocketChannel为非阻塞的(熟悉Java NIO的都知道如果不设置为false,启动多路复用器会报异常)

 

 

 

  •  

  •  //上面super调用的父类方法

  • protected AbstractChannel(Channel parent) {

  •         this.parent = parent;

  • // 非配id,该id全局唯一

  •         id = DefaultChannelId.newInstance();

  • // 初始化Unsafe, Server生成的Unsafe类为NioMessageUnsafe,Unsafe属于较底层的操作,不对应用开放

  • // 它处理的各种操作:register、bind、connect、disconnect、close、deregister,beginRead、write、flush

  •         unsafe = newUnsafe();

  • // 创建pipeline

  •         pipeline = new DefaultChannelPipeline(this);

  •     }

 

newUnsafe()方法调用

在AbstractChannel类中,newUnsafe()是一个抽象方法

protected abstract AbstractUnsafe newUnsafe();

 

们找到AbstractNioMessageChannel类中有newUnsafe()的实现

@Overrideprotected AbstractNioUnsafe newUnsafe() {

return new NioMessageUnsafe();

}

 

此方法返回一个NioMessageUnsafe实例对象,而NioMessageUnsafe是AbstractNioMessageChannel的内部类:

private final class NioMessageUnsafe extends AbstractNioUnsafe {

 

private final List<Object> readBuf = new ArrayList<Object>();

 

@Override

public void read() {

assert eventLoop().inEventLoop();

final ChannelConfig config = config();

final ChannelPipeline pipeline = pipeline();

final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();

allocHandle.reset(config);

 

boolean closed = false;

Throwable exception = null;

try {

try {

do {

int localRead = doReadMessages(readBuf);

if (localRead == 0) {

break;

}

if (localRead < 0) {

closed = true;

break;

}

 

allocHandle.incMessagesRead(localRead);

} while (allocHandle.continueReading());

} catch (Throwable t) {

exception = t;

}

 

int size = readBuf.size();

for (int i = 0; i < size; i ++) {

readPending = false;

pipeline.fireChannelRead(readBuf.get(i));

}

readBuf.clear();

allocHandle.readComplete();

pipeline.fireChannelReadComplete();

 

if (exception != null) {

closed = closeOnReadError(exception);

 

pipeline.fireExceptionCaught(exception);

}

 

if (closed) {

inputShutdown = true;

if (isOpen()) {

close(voidPromise());

}

}

} finally {

if (!readPending && !config.isAutoRead()) {

removeReadOp();

}

}

}

}

 

====================unsafa初始化结束=================

 

 

====================pipeline初始化=======================

 

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);

 

head.next = tail;

tail.prev = head;

}

 

 

 

=========================pipeline初始化结束====================

 

protected DefaultChannelPipeline(Channel channel) {

    this.channel = (Channel)ObjectUtil.checkNotNull(channel, "channel");

    this.succeededFuture = new SucceededChannelFuture(channel, (EventExecutor)null);

    this.voidPromise = new VoidChannelPromise(channel, true);

    this.tail = new DefaultChannelPipeline.TailContext(this);

    this.head = new DefaultChannelPipeline.HeadContext(this);

    this.head.next = this.tail;

    this.tail.prev = this.head;

}

此DefaultChannelPipeline对象会绑定NioServerSocketChannel对象,并初始化了HeadContext及TailContext对象。

 

 

final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {

TailContext(DefaultChannelPipeline pipeline) {

super(pipeline, (EventExecutor)null, DefaultChannelPipeline.TAIL_NAME, true, false);

this.setAddComplete();

}

 

final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler {

private final Unsafe unsafe;

 

HeadContext(DefaultChannelPipeline pipeline) {

super(pipeline, (EventExecutor)null, DefaultChannelPipeline.HEAD_NAME, false, true);

this.unsafe = pipeline.channel().unsafe();

this.setAddComplete();

}

 

 

 

由以上源码分析可知 channel = this.channelFactory.newChannel()方法会通过反射产生一个severSocketChannel实例,该实例在实例化过程中会默认监听accept事件(16),同时设置为非阻塞的,

(channel里就有unsafe以及pipeline(tail以及head都是在此时初始化的),这就会随着channel的初始化而初始化)

 

Socketchannel实例的产生和上面的一样,只不过注册是的事件是1也就是read事件,而不是accept事件

 

Channel初始化总结:

1、NioServerSocketChannel对象内部绑定了Java NIO创建的ServerSocketChannel对象;

2、Netty中,每个channel都有一个unsafe对象,此对象封装了Java NIO底层channel的操作细节;

3、Netty中,每个channel都有一个pipeline对象,此对象就是一个双向链表

=========================================Channel实例化产生结束=========================================================================

 

 

 

 

 

 

 

 

 

 

 

 

 

第二步 绑定用户的handler  init()方法  具体可看前面的serverbootStrap的init方法或者bootstrap的init方法(包括handler的添加)。

主要作用就是:

  1. 设置serverChannel的选项参数

  2. 设置serverChannel的属性键值对

  3. 添加处理serverChannel的IO事件处理器

仅仅在serverBootStrap中有所不同,在第三步会在最后添加一个其内部类ServerBootstrapAcceptor的handler事件。这个handler是一个inbound事件,会在accept触发之后,由于管道的传递性,会将此channel注册到workerGroup中去。(获取连接后,进行初始化)

 

 

===============================================init()方法结束====================================================

 第三步将channel(服务端则是serversocketchannel)绑定到boss线程:

 ChannelFuture regFuture = this.config().group().register(channel);

 

this,config()是ServerBootStrap或者bootStrap实现的,返回其本身实例,主要是为了暴露出各种参数,配置

this,config().group可以看作为serverbootstrap/bootstrap.group()即eventloopGroup.register(channel),注意这个eventloopgroup是bossGroup,这是因为要将上面初始化好的channel注册到bossChannel上,而且整个initAndRegister方法是在AbstractBootStrap类里的,而在初始化时,此group是bossgroup,也就是NioEventLoopGroup

 

 

NioEventLoopGroup的register()方法是其父类MultithreadEventLoopGroup实现的。

 

public ChannelFuture register(Channel channel) {

return this.next().register(channel);

}

 

 

public EventExecutor next() {

return this.chooser.next();

}

 

chooser类是在一开始初始化NioEventLoopGroup时初始化的,是用来在EventLoopGroup选择一个eventLoop的策略,是2的幂次方就是&否则是%。(具体的EventLoop源码在后面有一个专门的章节进行分析

1、children:EventExecutor数组,保存eventLoop。

2、chooser:从children中选取一个eventLoop的策略

 

 

最终调用了NioEventLoop的register()方法,最终调用的是:channel.unsafe().register(this, promise);(这个方法是在abstractChannel里执行的,在上面的channelfactory里已经初始化过了)  这行代码最终会调用AbstractChannel.AbstractUnsafe.register(EventLoop eventLoop, final ChannelPromise promise)方法:(具体的EventLoop源码在后面有一个专门的章节进行分析,在这里就是直接说出结果调用unsafe的register)。

其次中间应该会调用singleThreadEventLoop的register执行了eventloop的线程,进行轮询操作,反正是在注册之后就开始轮询了

 

public final void register(EventLoop eventLoop, final ChannelPromise promise) {

if (eventLoop == null) {

throw new NullPointerException("eventLoop");

} else if (AbstractChannel.this.isRegistered()) {//判断是否已经注册过了,即一个channel只能对用一个eventloop

promise.setFailure(new IllegalStateException("registered to an event loop already"));

} else if (!AbstractChannel.this.isCompatible(eventLoop)) {//判断是否兼容

promise.setFailure(new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));

} else {

AbstractChannel.this.eventLoop = eventLoop;//该channel持有一个eventLoop线程,注册到channel

if (eventLoop.inEventLoop()) {//判断当前线程是否是EventloopGroup里的线程

this.register0(promise);

} else {

try {

eventLoop.execute(new Runnable() {

public void run() {

AbstractUnsafe.this.register0(promise);

}

});

} catch (Throwable var4) {

AbstractChannel.logger.warn("Force-closing a channel whose registration task was not accepted by an event loop: {}", AbstractChannel.this, var4);

this.closeForcibly();

AbstractChannel.this.closeFuture.setClosed();

this.safeSetFailure(promise, var4);

}

}

 

}

}

 

 

AbstractChannel.AbstractUnsafe.register0():

private void register0(ChannelPromise promise) {

try {

if (!promise.setUncancellable() || !this.ensureOpen(promise)) {

return;

}

 

boolean firstRegistration = this.neverRegistered;

//真正的注册方法

AbstractChannel.this.doRegister();

this.neverRegistered = false;//注册过了

AbstractChannel.this.registered = true;//表示已经注册到了eventloop中去了。

 

AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();//表示可以接收新的任务了?

this.safeSetSuccess(promise);

//触发channel的注册事件

//Netty的HeadHandler不需要处理ChannelRegistered事件,所以,直接调用下一个Handler,当ChannelRegistered事件传递到TailHandler后结束,TailHandler也不关心ChannelRegistered事件

AbstractChannel.this.pipeline.fireChannelRegistered();

 

// 只有从未注册的channel才会触发channelActive,避免连接注销并重新注册时多次触发channelActive。

// 注意后面还会出现fireChannelActive方法的调用,正常的第一次启动应该是触发后面那个fireChannelActive而不是这个

 

if (AbstractChannel.this.isActive()) {//判断是否已经绑定了 其中isActive()是一个多态方法,如果是服务端则,判断监听是否启动;如果是客户端,判断TCP连接是否完成。ChannelActive事件在ChannelPipeline()传递,完成之后根据配置决定是否自动触发Channel的读操作。

 

if (firstRegistration) {//是否是第一次绑定

// 这里和前面的ServerSocketChannel分析一样,最终会触发unsafe.beginRead()

AbstractChannel.this.pipeline.fireChannelActive();

} else if (AbstractChannel.this.config().isAutoRead()) {

this.beginRead();

}

}

} catch (Throwable var3) {

this.closeForcibly();

AbstractChannel.this.closeFuture.setClosed();

this.safeSetFailure(promise, var3);

}

 

}

 

 

=================================注册方法分析===================================================

最终最终的注册方法:AbstractNioChannel.doRegister():

protected void doRegister() throws Exception {

boolean selected = false;

 

while(true) {

try {

this.selectionKey = this.javaChannel().register(this.eventLoop().unwrappedSelector(), 0, this);

return;

} catch (CancelledKeyException var3) {

// 如果发生异常则强制执行Selector.selectNow()方法使 "canceled"的SelectionKey从Selector中移除

if (selected) {

throw var3;

}

// 强制Selector调用select now,防止取消的SelectionKey未真正取消(因为还没有调用到Select.select(..))

this.eventLoop().selectNow();

selected = true;

}

}

}

循环执行selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);

一直到成功为止。

 

在abstractNiochannel类中实现:

protected SelectableChannel javaChannel() {

return this.ch;

}

 

private  final SelectableChannel ch;

 

 

在abstractNiochannel类中实现:

register(eventLoop().unwrappedSelector(), 0, this);是在 AbstractSelectableChannel实现的

public final SelectionKey register(Selector var1, int var2, Object var3) throws ClosedChannelException {

Object var4 = this.regLock;

synchronized(this.regLock) {

if (!this.isOpen()) {

throw new ClosedChannelException();

} else if ((var2 & ~this.validOps()) != 0) {

throw new IllegalArgumentException();

} else if (this.blocking) {

throw new IllegalBlockingModeException();

} else {

SelectionKey var5 = this.findKey(var1);

if (var5 != null) {

var5.interestOps(var2);

var5.attach(var3);

}

 

if (var5 == null) {

Object var6 = this.keyLock;

synchronized(this.keyLock) {

if (!this.isOpen()) {

throw new ClosedChannelException();

}

 

var5 = ((AbstractSelector)var1).register(this, var2, var3); //注册的参数分别是channel,事件var2,event

this.addKey(var5);

}

}

 

return var5;

}

}

}

 

 

大伙儿可能会很诧异,应该注册OP_ACCEPT(16)到多路复用器上,怎么注册0呢?0表示只注册,不监听任何网络操作。这样做的原因如下:

  • 注册方法是多态的,它既可以被NioServerSocketChannel用来监听客户端的连接接入,也可以用来注册SocketChannel,用来监听网络读或者写操作;

  • 通过SelectionKey的interestOps(int ops)方法可以方便的修改监听操作位。所以,此处注册需要获取SelectionKey并给AbstractNioChannel的成员变量selectionKey赋值

 

 

======================注册方法分析结束=================================================

 

 

 

 

 

 

 

 

 

 

 

 

不管是注册到boss线程还是work线程,都会在注册成功之后调用AbstractChannel.this.pipeline.fireChannelRegistered();方法  

以HttpSnoopServer为例,childHandler为HttpSnoopServerInitializer,初始化是NioSocketChannel的pipeline中只有tail,head及HttpSnoopServerInitializer的实例,

tail和head中的channelRegisterd除了传递或者停止外没有其他用处,因此此处的channelRegisterd主要逻辑在HttpSnoopServerInitializer的channelRegistered方法:

* public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {

* ChannelPipeline pipeline = ctx.pipeline();

* boolean success = false;

* try {

* // initChannel主要是初始化channel对应的pipeline

*  initChannel((C) ctx.channel());

* // 初始化完成后将自身移除

* pipeline.remove(this);

* // channelRegistered属于inbound事件,注册后调用一次该方法,这样所有用户添加的handler可以感知到此事件

* ctx.fireChannelRegistered();

* success = true;

* } catch (Throwable t) {

* logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), t);

* } finally {

* if (pipeline.context(this) != null) {

* pipeline.remove(this);

* }

* if (!success) {

* ctx.close();

* }

* }

* }

* // 此方法在HttpSnoopServerInitializer中

* public void initChannel(SocketChannel ch) {

*         ChannelPipeline p = ch.pipeline();

*         if (sslCtx != null) {

*             p.addLast(sslCtx.newHandler(ch.alloc()));

*         }

*         p.addLast(new HttpRequestDecoder());

*         // Uncomment the following line if you don't want to handle HttpChunks.

*         //p.addLast(new HttpObjectAggregator(1048576));

*         p.addLast(new HttpResponseEncoder());

*         // Remove the following line if you don't want automatic content compression.

*         //p.addLast(new HttpContentCompressor());

*         p.addLast(new HttpSnoopServerHandler());

*     }

 

 

 

 

fireChannelRegistered()调用的仍然是beginRead()方法

================前面的注册之后就开始读this.beginRead();===================================

public final void beginRead() {

assertEventLoop();

 

if (!isActive()) {

return;

}

 

try {

doBeginRead();

} catch (final Exception e) {

invokeLater(new Runnable() {

@Override

public void run() {

pipeline.fireExceptionCaught(e);

}

});

close(voidPromise());

}

}

由于不同类型的Channel对读的准备工作不同,因此doBeginRead也是个多态方法。

对于NIO通信,无论是客户端,还是服务端,都要设置网络监听操作位为自己感兴趣的,对于NioServerSocketChannel感兴趣的是  OP_ACCEPT(16),于是修改操作位

 

 

刚开始是注册了accept(16),后来在accept之后,就又会进行一次管道的传递,调用这个方法,进行设置为reead事件了

@Override

protected void doBeginRead() throws Exception {

// Channel.read() or ChannelHandlerContext.read() was called

final SelectionKey selectionKey = this.selectionKey;

if (!selectionKey.isValid()) {

return;

}

 

readPending = true;

 

final int interestOps = selectionKey.interestOps();

if ((interestOps & readInterestOp) == 0) {

selectionKey.interestOps(interestOps | readInterestOp);//一个是0一个是前面的16,最终仍然是16 

}

}

 

 

 

 

============================this.beginRead()结束==================================================

 

 

 

 

 

 

该实现是通过spi的机制实现的,已经到了最底层了

==================================到这儿就是注册完成了====================================

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值