protectedvoidrun(){int selectCnt =0;for(;;){try{int strategy;try{
strategy = selectStrategy.calculateStrategy(selectNowSupplier,hasTasks());switch(strategy){caseSelectStrategy.CONTINUE:continue;caseSelectStrategy.BUSY_WAIT:// fall-through to SELECT since the busy-wait is not supported with NIOcaseSelectStrategy.SELECT:long curDeadlineNanos =nextScheduledTaskDeadlineNanos();if(curDeadlineNanos ==-1L){
curDeadlineNanos =NONE;// nothing on the calendar}
nextWakeupNanos.set(curDeadlineNanos);try{if(!hasTasks()){// 阻塞在此。等待消息到来。
strategy =select(curDeadlineNanos);}}finally{// This update is just to help block unnecessary selector wakeups// so use of lazySet is ok (no race condition)
nextWakeupNanos.lazySet(AWAKE);}// fall throughdefault:}}catch(IOException e){// If we receive an IOException here its because the Selector is messed up. Let's rebuild// the selector and retry. https://github.com/netty/netty/issues/8566rebuildSelector0();
selectCnt =0;handleLoopException(e);continue;}
selectCnt++;
cancelledKeys =0;
needsToSelectAgain =false;finalint ioRatio =this.ioRatio;boolean ranTasks;if(ioRatio ==100){try{if(strategy >0){processSelectedKeys();}}finally{// Ensure we always run tasks.
ranTasks =runAllTasks();}}elseif(strategy >0){finallong ioStartTime =System.nanoTime();try{processSelectedKeys();}finally{// Ensure we always run tasks.finallong ioTime =System.nanoTime()- ioStartTime;
ranTasks =runAllTasks(ioTime *(100- ioRatio)/ ioRatio);}}else{
ranTasks =runAllTasks(0);// This will run the minimum number of tasks}if(ranTasks || strategy >0){if(selectCnt >MIN_PREMATURE_SELECTOR_RETURNS&& logger.isDebugEnabled()){
logger.debug("Selector.select() returned prematurely {} times in a row for Selector {}.",
selectCnt -1, selector);}
selectCnt =0;}elseif(unexpectedSelectorWakeup(selectCnt)){// Unexpected wakeup (unusual case)
selectCnt =0;}}catch(CancelledKeyException e){// Harmless exception - log anywayif(logger.isDebugEnabled()){
logger.debug(CancelledKeyException.class.getSimpleName()+" raised by a Selector {} - JDK bug?",
selector, e);}}catch(Error e){throw e;}catch(Throwable t){handleLoopException(t);}finally{// Always handle shutdown even if the loop processing threw an exception.try{if(isShuttingDown()){closeAll();if(confirmShutdown()){return;}}}catch(Error e){throw e;}catch(Throwable t){handleLoopException(t);}}}}// 有消息过来时就会执行此方法。privatevoidprocessSelectedKeysOptimized(){// 遍历执行channel。for(int i =0; i < selectedKeys.size;++i){finalSelectionKey k = selectedKeys.keys[i];// null out entry in the array to allow to have it GC'ed once the Channel close// See https://github.com/netty/netty/issues/2363
selectedKeys.keys[i]=null;finalObject a = k.attachment();if(a instanceofAbstractNioChannel){processSelectedKey(k,(AbstractNioChannel) a);}else{@SuppressWarnings("unchecked")NioTask<SelectableChannel> task =(NioTask<SelectableChannel>) a;processSelectedKey(k, task);}if(needsToSelectAgain){// null out entries in the array to allow to have it GC'ed once the Channel close// See https://github.com/netty/netty/issues/2363
selectedKeys.reset(i +1);selectAgain();
i =-1;}}}privatevoidprocessSelectedKey(SelectionKey k,AbstractNioChannel ch){...if((readyOps &(SelectionKey.OP_READ|SelectionKey.OP_ACCEPT))!=0|| readyOps ==0){// 执行read。
unsafe.read();}...}publicfinalvoidread(){...try{do{...// 依次执行管道的ChannelRead。
pipeline.fireChannelRead(byteBuf);...}while(allocHandle.continueReading());...}
SimpleChannelInboundHandler抽象类自己做了一个包装。
publicabstractclassSimpleChannelInboundHandler<I>extendsChannelInboundHandlerAdapter{privatefinalTypeParameterMatcher matcher;privatefinalboolean autoRelease;/**
* Returns {@code true} if the given message should be handled. If {@code false} it will be passed to the next
* {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
*/publicbooleanacceptInboundMessage(Object msg)throwsException{return matcher.match(msg);}// 可以指定一个泛型进来。 会将msg强转为指定泛型。然后执行子类的channelRead0,即我们自定义的handler。@OverridepublicvoidchannelRead(ChannelHandlerContext ctx,Object msg)throwsException{boolean release =true;try{if(acceptInboundMessage(msg)){@SuppressWarnings("unchecked")I imsg =(I) msg;channelRead0(ctx, imsg);}else{
release =false;
ctx.fireChannelRead(msg);}}finally{if(autoRelease && release){ReferenceCountUtil.release(msg);}}}/**
* Is called for each message of type {@link I}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
* belongs to
* @param msg the message to handle
* @throws Exception is thrown if an error occurred
*/protectedabstractvoidchannelRead0(ChannelHandlerContext ctx,I msg)throwsException;}