An overview of the

The Reactor model I have learned before only understands how the server side processes a connection into a workergroup, so what is the real process of processing a specific request

The basic concept

  1. We know that data is read through channels. Netty defines a number of IO events for channelsLife cycle function, Netty encapsulates these lifecycle functions inHandlerThrough the mode of responsibility chain encapsulation in onepipelineIn the. When the corresponding IO event is triggered in the channel, it is called in the pipelineHead or tailIs passed to the next level by the corresponding handler.
  2. Netty divides I/O events into two types. One is that Netty reads data from the network and calls it InBound. One is that Netty writes data to the network as OutBound. Handler is also dividedChannelInBoundHandler and ChannelOutBoundHandler, they each have different life cycle functions
  3. Pipeline is to give a bidirectional linked list, with two Pointers,Inbound events are propagated backwards from the head node, and outbound events are propagated forwards from the tail node
  4. To make the handler more flexible, Netty has added a layer around itHandlerContext.context allows a handler in a lifecycle methodDirectly changing the flow of dataFor example, after reading the data, you can ask the context to write the data out. Then the data flow changes from inbound to outbound

InboundHandler

public interface ChannelInboundHandler extends ChannelHandler {# channel register toeventLoop
    void channelRegistered(ChannelHandlerContext ctx) throws Exception; # channel unregister from eventloopvoid channelUnregistered(ChannelHandlerContext ctx) throws Exception; The # channel connection has been establishedvoid channelActive(ChannelHandlerContext ctx) throws Exception; # channel terminates the connectionvoid channelInactive(ChannelHandlerContext ctx) throws Exception; # channel reads data from the networkvoid channelRead(ChannelHandlerContext ctx, Object msg) throws Exception; # channel Finishes reading datavoid channelReadComplete(ChannelHandlerContext ctx) throws Exception; Call this method when an exception occurs while reading datavoid exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
Copy the code

Let’s look at the lifecycle call source code.

  1. ChannelRegistered: In the AbstractChannel method register method
private void register0(ChannelPromise promise) {
    try{# register a channel to an eventloop and doRegister() to a selector; # after the registration is called pipeline fireChannelRegistered method of pipeline. The fireChannelRegistered ();if (isActive()) {
            if(firstRegistration) {# if it is active will call fireChannelActive method pipeline. FireChannelActive (); }else if (config().isAutoRead()) {

            }
        }
    } catch (Throwable t) {
      
    }
}
Copy the code

So let’s look at the source of pipeline

@Override
public final ChannelPipeline fireChannelRegistered(a) {# preach a pipeline head node, that is transmitted from the very beginning of AbstractChannelHandlerContext invokeChannelRegistered (head);return this;
}
Copy the code

The pipeline calls static methods of the context. The following are the calls within the context

# AbstractChannelHandlerContext invokeChannelRegistered methodstatic void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
    EventExecutor executor = next.executor();
    if(executor. InEventLoop ()) {# call head node invokeChannelRegistered method again next. InvokeChannelRegistered (); }else {
        executor.execute(new Runnable() {
            @Override
            public void run(a) { next.invokeChannelRegistered(); }}); }}private void invokeChannelRegistered(a) {
    if (invokeHandler()) {
        try{# get the handler of the head node and call handler's hook function ((ChannelInboundHandler) handler()). ChannelRegistered (this);
        } catch(Throwable t) { notifyHandlerException(t); }}else{ fireChannelRegistered(); }}Copy the code

Finally, we call our custom handler hook function, especially if we don’t call super.channelregistered (CTX) in this function; Then the broadcast will be terminated

@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    System.out.println("channelRegistered----Inbound1");
    super.channelRegistered(ctx);
}
Copy the code

If we continue to relay, the context will find the next inbound context and execute the method.

@Override
public ChannelHandlerContext fireChannelRegistered(a) {
    invokeChannelRegistered(findContextInbound());
    return this;
}

private AbstractChannelHandlerContext findContextInbound(a) {
    AbstractChannelHandlerContext ctx = this;
    do {
        ctx = ctx.next;
    } while(! ctx.inbound);return ctx;
}
Copy the code

outboundHandler

public interface ChannelOutboundHandler extends ChannelHandler {# triggered when the bond port succeedsvoid bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception; Client connection to server triggeredvoid connect( ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception; Disconnect triggervoid disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

    void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
   
    void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
    
    void read(ChannelHandlerContext ctx) throws Exception;

    void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;

    void flush(ChannelHandlerContext ctx) throws Exception;
}
Copy the code

Outbound and inbound are triggered at different times, so they are rarely used and will be repaired later.

ChannelInitializer

In BootstrapServer, we tend to create a ChannelInitializer ChildHandler. Then add handlers to the pipeline for the new channel in the initChannel method. Let’s look at the process

  1. The ChannelInitializer is stored in serverBootStrap
public static void main(String[] args) throws Exception {

    new ServerBootstrap()
            .group(new NioEventLoopGroup(), newNioEventLoopGroup ()). The channel (NioServerSocketChannel. Class) # save childHandler. ChildHandler (new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new Inbound1());
                    ch.pipeline().addLast(new OutBound1());
                    ch.pipeline().addLast(new Inbound2());
                    ch.pipeline().addLast(new OutBound2());
                    ch.pipeline().addLast(new Inbound3());
                    ch.pipeline().addLast(new OutBound3());
                }
            }).bind(9090).sync().channel().closeFuture().sync();
}
Copy the code
  1. The ServerBootStrap channelRead method is triggered when the client connects to the server
public void channelRead(ChannelHandlerContext ctx, Object msg) This is the client channelfinalChannel child = (Channel) msg; # add ChannelInitializer child.pipeline().addLast(childHandler); }Copy the code
  1. Then there is the reactor’s series of things, this channel was added a handler by BossGroup and dropped to the WorkerGroup, and then it was ready to register to the Channel of the WorkerGroup
private void register0(ChannelPromise promise) {
    try{# register a channel to an eventloop and doRegister() to a selector; # call pipeline to add the handler method pipeline. InvokeHandlerAddedIfNeeded (); # after the registration is called pipeline fireChannelRegistered method of pipeline. The fireChannelRegistered ();if (isActive()) {
            if(firstRegistration) {# if it is active will call fireChannelActive method pipeline. FireChannelActive (); }else if (config().isAutoRead()) {

            }
        }
    } catch (Throwable t) {
      
    }
}
Copy the code
  1. And then finally fell on pipelinecallHandlerAdded0Method, which gets handler to execute the handlerAdded method

5. Methods in pipeline

conclusion

These several processes on the general combing finished, sum up

  1. An initHandler was passed when ServerBootStrap was created
  2. The initHandler is added to the client channel pipeline when the server receives the client connection
  3. The client then calls the inithandler in the pipeline when it is ready to register with the eventLoop, and the client pipeline is then added to a user-defined handler.
  4. And then I’m going to remove this initialized handler