EventLoopGroup创建OK后,启动的第一步就算完成了,接下来该进行bind、listen操作了 。
ServerBootstrap流程
bind操作
bind操作是ServerBootstrap流程重要的一环,bind流程涉及到NioChannel的创建、初始化和注册(到Selector),启动NioEventLoop,之后就可以对外提供服务了 。
public ChannelFuture bind(SocketAddress localAddress) { validate(); // 参数校验 return doBind(localAddress);}private ChannelFuture doBind(final SocketAddress localAddress) { // 1. 初始化注册操作 final ChannelFuture regFuture = initAndRegister(); final Channel channel = regFuture.channel(); if (regFuture.cause() != null) { return regFuture; }// 2. doBind0操作 if (regFuture.isDone()) { // register已完成,这里直接调用doBind0 ChannelPromise promise = channel.newPromise(); doBind0(regFuture, channel, localAddress, promise); return promise; } else { // register还未完成,注册listener回调,在回调中调用doBind0 final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel); regFuture.addListener(new ChannelFutureListener() { /** * channel register完成(注册到Selector并且调用了invokeHandlerAddedIfNeeded)之后,* 会调用safeSetSuccess,触发各个ChannelFutureListener,最终会调用到这里的operationComplete方法 */ @Override public void operationComplete(ChannelFuture future) throws Exception { Throwable cause = future.cause(); if (cause != null) { promise.setFailure(cause); } else { promise.registered(); doBind0(regFuture, channel, localAddress, promise); } } }); return promise; }}这里涉及到2个操作,一个是channel的创建、初始化、注册操作,另一个是bind操作,下面兵分两路,分别来讲 。
注意,这里如果main线程执行到regFuture.isDone()时,register还未完成,那么main线程是不会直接调用bind操作的,而是往regFuture上注册一个Listenner,这样channel register完成(注册到Selector并且调用了invokeHandlerAddedIfNeeded)之后,会调用safeSetSuccess,触发各个ChannelFutureListener,最终会调用到这里的operationComplete方法,进而在执行bind操作 。channel初始化、注册操作
final ChannelFuture initAndRegister() { Channel channel = null; try { // 1.创建(netty自定义)Channel实例,并初始化 // channel为 NioServerSocketChannel 实例,NioServerSocketChannel的父类AbstractNioChannel保存有nio的ServerSocketChannel channel = channelFactory.newChannel(); // 2.初始化channel() init(channel); } catch (Throwable t) { }// 3.向Selector注册channel ChannelFuture regFuture = config().group().register(channel); if (regFuture.cause() != null) { if (channel.isRegistered()) { channel.close(); } else { channel.unsafe().closeForcibly(); } }return regFuture;}这里重点关注下初始化channel流程,主要操作是设置channel属性、设置channel.pipeline的ChannelInitializer,注意,ChannelInitializer是在channel注册到selector之后被回调的 。
/** * 初始channel属性,也就是ChannelOption对应socket的各种属性 。* 比如 SO_KEEPALIVE SO_RCVBUF ... 可以与linux中的setsockopt函数对应起来 。* 最后将ServerBootstrapAcceptor添加到对应channel的ChannelPipeline中 。*/@Overridevoid init(Channel channel) throws Exception { final Map, Object> options = options0(); synchronized (options) { setChannelOptions(channel, options, logger); }ChannelPipeline p = channel.pipeline(); // 获取childGroup和childHandler,传递给ServerBootstrapAcceptor final EventLoopGroup currentChildGroup = childGroup; final ChannelHandler currentChildHandler = childHandler; final Entry, Object>[] currentChildOptions; final Entry, Object>[] currentChildAttrs; synchronized (childOptions) { currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0)); } synchronized (childAttrs) { currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0)); }p.addLast(new ChannelInitializer() { /** * 在register0中,将channel注册到Selector之后,会调用invokeHandlerAddedIfNeeded,* 进而调用到这里的initChannel方法 */ @Override public void initChannel(final Channel ch) throws Exception { final ChannelPipeline pipeline = ch.pipeline(); ChannelHandler handler = config.handler(); if (handler != null) { pipeline.addLast(handler); }// 这里注册一个添加ServerBootstrapAcceptor的任务 ch.eventLoop().execute(new Runnable() { @Override public void run() { // 添加ServerBootstrapAcceptor pipeline.addLast(new ServerBootstrapAcceptor( ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)); } }); } });}channel初始化之后就该将其注册到selector,即下面的register流程:
public ChannelFuture register(Channel channel) { // next()挑选一个EventLoop,默认轮询选择某个NioEventLoop return next().register(channel);}public ChannelFuture register(final ChannelPromise promise) { promise.channel().unsafe().register(this, promise); return promise;}// AbstractChannelpublic final void register(EventLoop eventLoop, final ChannelPromise promise) { AbstractChannel.this.eventLoop = eventLoop;// 直接执行register0或者以任务方式提交执行 // 启动时,首先执行到这里的是main线程,所以是以任务的方式来提交执行的 。// 也就是说,该任务是NioEventLoop第一次执行的任务,即调用register0 if (eventLoop.inEventLoop()) { register0(promise); } else { // 往NioEventLoop中(任务队列)添加任务时,如果NioEventLoop线程还未启动,则启动该线程 eventLoop.execute(new Runnable() { @Override public void run() { register0(promise); } }); }}
推荐阅读
- 如何开淘宝店步骤开淘宝网店 淘宝店铺怎么开店流程
- 壁挂炉冻了还能启动吗,壁挂炉冻了怎么解冻
- 怎么把淘宝店转让 接别人转让的店铺流程
- 开水果店的流程 淘宝水果店怎么开
- 淘宝个人店铺过户流程 淘宝店铺过户需要什么条件
- 十大紫砂茗壶展评启动
- 晋中,重走晋商茶路活动启动
- 淘宝商家认证流程 淘宝企业店铺认证流程
- Java JVM启动参数大全
- 跨境电商物流操作流程 货代操作流程