In this article, we will take a look at the process of the Netty server listening on the port.

ChannelFuture future = bootstrap.bind(9081).sync();
Copy the code

ServerBootstrap’s parent class, AbstractBootstrap, is called doBind(), which uses the bind() method provided by ServerBootstrap to bind a listener port.

Following up with the doBind() method, we first call initAndRegister(), which, as we saw in previous chapters, creates a new channel through the NioServerSocketChannel constructor, and then calls the init() method implemented by the subclass, Initialize this channel. In addition to setting options and childOption properties, the most important initialization process is to add ServerBootstrapAcceptor to the NioServerSocketChannel pipeline. The ServerBootstrapAcceptor is a ChannelInboundHandler that listens for OP_ACCEPT events from client connections. One thing to note is that the initChannel method is not executed here, so when is it executed? So let’s move on.

Once the NioServerSocketChannel initialization is complete, the registration process is ready to proceed. In the process of looking at the source code, because it is interface oriented programming, so many times we see is not the implementation class, so to figure out which specific implementation class is, you can execute the code to see the specific runtime results, but also through the method name reasonable guess. For example the following code, we can guess the register method is invoked in MultithreadEventLoopGroup method

config().group().register(channel)
Copy the code

Continue with the register() method implementation

@Override
public ChannelFuture register(Channel channel){
    return next().register(channel);
}
Copy the code

In the next () method is invoked the MultithreadEventExecutorGroup implementation, from bossGroup thread pool, choose a executor, here and in the two cases, one kind is bossGroup to specify the number of threads, as an integer power of 2, The other way is that the number is not an integer power of two, but it’s all polling.

Finally realize the register, in AbstractChannel register0 packaging into a Runnable, using SingleThreadEventExecutor to execution, is the key here!!!!!

Follow up with the eventloop. execte method

@Override public void execute(Runnable task) { ObjectUtil.checkNotNull(task, "task"); execute(task, ! (task instanceof LazyRunnable) && wakesUpForTask(task)); }Copy the code

At this point, it’s important to remember that Task is a register0 registration task wrapped in AbstractChannel. Add the task to the task queue and continue with the startThread() method.

Call the doStartThread() method to start a new thread to execute the task.

In doStartThread () method, and encapsulates a task, the task is encapsulated in SingleThreadEventExecutor. Enclosing the run (), here to perform a task executor is ThreadExecutorMap instance, Bind the task to eventExecutor and encapsulate it into a new task.

Are there a lot of little question marks in your mind when you look at this? Who am I? Where I am? Why are there so many tasks mixed together? In fact, if you want to understand Netty’s threading model, you must constantly debug, interrupt points, step by step tracking execution, to clear the fog to see the reality.

In this binding process, why only see the wrapping task, but not the execution of the task? Where exactly do these tasks begin? Now, we’re not far from the answer.

executor.execute(apply(command,eventExecutor));
Copy the code

This is the whole task chain master switch, calls the ThreadPerTaskExecutor. Exexute () method, knocking down the entire domino: create a new thread and begins to execute.

@Override
public void execute(Runnable command){
    threadFactory.newThread(command).start();
}
Copy the code

Do you remember what the mission was? Is SingleThreadEventExecutor. Enclosing the run (), this method will start NioEventLoop. The run () method, start the infinite loop to polling tasks, perform a task.

Look at this, remember what we were doing? We are tracking the flow of listening on the port, and remember we wrapped register0() into a task queue. As we can see from the figure above, the loop is doing its job. So let’s go back to the method register0() and follow up with doRegister(): it’s actually NIO’s channel, registered with selector, and registered with an event of type 0, which means it’s not interested in anything. Should it be interested in OP_ACCEPT? And then we look down.

After doRegister, the client events are read.

Follow up AbstractNioChannel. DoBeginRead () method: to add OP_ACCEPT SelectionKey events, so far, the entire Netty to port to monitor process is completed.

Netty thread model, too abstract, task set task execution way makes people look very difficult to understand, the author was designing this model, really curious, what kind of way of thinking, to come up with this model? This process, only after watching several times, can a little bit of understanding, thanks to the teaching of Netty teacher Lei, taught Netty course can make my understanding of Netty more clear. However, it is not enough to just listen to others. Only after careful deliberation and repeated interruption points and debug, can we understand one-tenth and two-tenth of the model. We also need to read more times to get a clearer understanding.