Netty version: netTY-4.1.74.final

1. The ChannelHandler is introduced

ChannelHandler has two main functions:

  • Processes I/O events and intercepts I/O operations, mainly for processing channels
  • Pass calls from the current ChannelHandler to the next ChannelHandler in the ChannelPipeline

The ChannelHandler inheritance diagram is as follows:

It can be seen from the above that there are two main categories:

  • ChannelInboundHandler

    Receives notification of inbound I/O operations

  • ChannelOutboundHandler

    Receive I/O outbound operation notification

Involving ChannelOutboundHandlerAdapter and ChannelInboundHandlerAdapter adapter is mainly provides a default implementation method.

ChannelDuplexHandler is a duplex processor with ChannelInboundHandler and ChannelOutboundHandler functions

2. Life cycle of ChannelHandler

ChannelHandler:

public interface ChannelHandler {
    
    void handlerAdded(ChannelHandlerContext ctx) throws Exception;

    void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
    
    @Deprecated
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

    @Inherited
    @Documented
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Sharable {
        // no value}}Copy the code

There are only three ways:

  • ChannelHandler#handlerAdded

    Triggered by being added to the live post

  • ChannelHandler#handlerRemoved

    Was removed from the context

  • ChannelHandler#exceptionCaught

    There is Throwable error throw error trigger

The ChannelHandler#exceptionCaught method has been marked expired and can be implemented with the ChannelInboundHandler#exceptionCaught method

To illustrate the process, use a server-side example:

package io.netty.example.discard;
    
import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
    
/** * Discards any incoming data. */
public class DiscardServer {
    
    private int port;
    
    public DiscardServer(int port) {
        this.port = port;
    }
    
    public void run(a) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); / / (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); / / (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) / / (3)
             .childHandler(new ChannelInitializer<SocketChannel>() { / / (4)
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new DiscardServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          / / (5)
             .childOption(ChannelOption.SO_KEEPALIVE, true); / / (6)
    
            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync(); / / (7)
    
            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        } finally{ workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); }}public static void main(String[] args) throws Exception {
        int port = 8080;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        }

        newDiscardServer(port).run(); }}Copy the code

Netty. IO /wiki/user-g…

This code is actually divided into two parts one is NioServerSocketChannel and SocketChannel. First, analyze the ChannelHandler in NioServerSocketChannel.

The code tells you that the ServerBootstrap#init method is called when NioServerSocketChannel is created. In this method there is code like this:

Create an instance of ChannelHandler (ChannelInitializer) to add to the ChannelPipeline for NioServerSocketChannel. DefaultChannelPipeline#addLast is called by tracing the ChannelPipeline#addLast method:

Then in DefaultChannelPipeline# callHandlerAdded0 method is invoked AbstractChannelHandlerContext# callHandlerAdded method:

Then get the ChannelHandler instance and call the handlerAdded method. That is, call the ChannelHandler#handlerAdded method. This completes the process from creating ChannelHandler to calling the ChannelHandler#handlerAdded method.

If the call DefaultChannelPipeline# the remove method, the final call is AbstractChannelHandlerContext# callHandlerRemoved in this method:

Call the ChannelHandler# handlerRemoved

For ChannelHandler#exceptionCaught there is a try catch for all ChannelHandler and subclass methods To capture and then execute abnormal AbstractChannelHandlerContext# invokeExceptionCaught method

This method calls ChannelHandler#exceptionCaught

The ChannelHandler#exceptionCaught method is marked as expired. Note the ChannelInboundHandler#exceptionCaught method. It may also be executed in ChannelInitializer#initChannel

Conclusion: The ChannelHandler#handlerAdded method occurs when a ChannelHandler is added to a ChannelPipeline, ChannelHandler#handlerRemoved mainly occurs when a ChannelHandler is removed from the ChannelPipeline, The ChannelHandler#exceptionCaught mainly occurs when the ChannelInboundHandler and ChannelOutboundHandler methods are executed incorrectly

3. The execution sequence of ChannelHandler methods

The ChannelHandler method here refers to the ChannelHandler method itself and the order of the ChannelInboundHandler and ChannelOutboundHandler methods. Take a look at the methods in each of the three classes:

ChannelHandler interface

type describe
handlerAdded Called when a ChannelHandler is added to the ChannelPipeline
handlerRemoved Called when a ChannelHandler is removed from the ChannelPipeline
exceptionCaught Called when an error occurs in the ChannelPipeline during processing

Netty defines the following two important ChannelHandler subinterfaces:

  • ChannelInboundHandler – Handles inbound data and various state changes
  • ChannelOutboundHandler – Handles outbound data and allows all operations to be intercepted

ChannelInboundHandler interface

type describe
channelRegistered Called when a Channel has registered with its EventLoop and is able to handle I/O
channelUnregistered Called when a Channel unlogs from its EventLoop and is unable to process any I/O
channelActive Called when a Channel is active; The Channel is connected/bound and ready to go
channelInactive Called when a Channel is out of the active state and no longer connects to its remote node
channelReadComplete Called when a read operation on a Channel completes
channelRead Called when reading data from a Channel
ChannelWritabilityChanged Called when a Channel’s writable state changes. The user can ensure that writes do not complete too quickly (to avoid outofMemoryErrors) or can resume writes when a Channel becomes writable again. The writability of a Channel can be detected by calling its isWritable() method. Writability related thresholds can be set using the channel.config ().setwritehighwatermark () and channel.config ().setwritelowwatermark () methods
userEventTriggered When ChannelnboundHandler. FireUserEventTriggered () method is invoked is called, because a POJO is to pass on scripture the ChannelPipeline

ChannelOutboundHandler interface

type describe
bind(ChannelHandlerContext,SocketAddress,ChannelPromise) Called when a request binds a Channel to a local address
connect(ChannelHandlerContext,SocketAddress,SocketAddress,ChannelPromise) Called when a request is made to connect a Channel to a remote node
disconnect(ChannelHandlerContext,ChannelPromise) Called when a request disconnects a Channel from a remote node
close(ChannelHandlerContext,ChannelPromise) Called when a request is made to close a Channel
deregister(ChannelHandlerContext,ChannelPromise) Called when the request unlogs a Channel from its EventLoop
read(ChannelHandlerContext) Called when a request reads more data from a Channel
flush(ChannelHandlerContext) Called when a request flushes enqueued data to a remote node via a Channel
write(ChannelHandlerContext,Object,ChannelPromise) Called when a request writes data to a remote node via a Channel

3.2 Parsing ChannelHandler method execution sequence from source code

This requires a longer length to explain, I in the article “Netty source code parsing -ChannelHandler method execution order” for detailed explanation.

4. Classification description of ChannelHandler

There are three main implementations of ChannelHandler:

  • ChannelInboundHandler: Handles inbound data and changes. The client or server receives data from the other side for processing.
  • ChannelOutboundHandler: handles outbound data and allows interception of all operations
  • ChannelDuplexHandler: Contains ChannelInboundHandler and ChannelOutboundHandler.

Derived from the above are decoders and encoders:

  • XXXXDecoder: mainly responsible for decoding the data in the network into the data required by the end, such as: ProtobufDecoder
  • XXXXEncoder: mainly responsible for encoding the structured data into the data format transmitted in the network, such as ProtobufEncoder

Decoders and encoders are also important components in Netty.

5. To summarize

  • ChannelHandler is bound to a Channel and is triggered by ChannelHandlerContext.
  • ChannelHandler intercepts I/O operations and I/O events, and connects multiple ChannelHandlers to form a call chain through a ChannelPipeline
  • ChannelHandler is divided into outbound and inbound processors, while deriving encoder and decoder.

I am ant back elephant, the article is helpful to you like to pay attention to me, the article has incorrect place please give correct comments ~ thank you