This is the 8th day of my participation in the August More Text Challenge. For details, see:August is more challenging
preface
First briefly understand the concept of ChannelPipeline and ChannelHandler.
Imagine an assembly line. When components enter from the head of the line and cross the line, workers on the line process the components in sequence, and the goods are assembled at the end of the line. Can be ChannelPipeline as the pipeline, ChannelHandler as the assembly line workers. The source component acts as an event, such as read,write, and so on.
In this article, we first talk about the relevant knowledge of ChannelHandler, and then enter the main body.
The body of the
ChannelHandler
ChannelHandler
The event is not handled, but is handled by its subclass:ChannelInboundHandler
Intercepting and handling inbound events,ChannelOutboundHandler
Intercepting and handling outbound events.ChannelHandler
andChannelHandlerContext
throughCombination or inheritanceAre used together in pairs. Events throughChannelHandlerContext
Active invocation such asfireXXX()
andwrite(msg)
Etc, propagating the event to the next handler.
Note: inbound events travel head to tail in the ChannelPipeline two-way list, and outbound events travel in the opposite direction.
ChannaleHandler is the top-level interface that does not handle inbound and outbound events, so the interface contains only the most basic methods:
Void handlerAdded(ChannelHandlerContext VAR1) throws Exception; void handlerAdded(ChannelHandlerContext VAR1) throws Exception; Void handlerRemoved(ChannelHandlerContext VAR1) throws Exception; @deprecated void exceptionCaught(ChannelHandlerContext VAR1, Throwable VAR2) throws Exception;Copy the code
Sharable comments:
When the client connects to the server, Netty creates a new ChannelPipeline to handle the events, and a ChannelPipeline contains several channelhandlers. If each client connection creates a new instance of ChannelHandler, when there are a large number of clients, the server will hold a large number of ChannelHandler instances. To do this, Netty provides the Sharable annotation. If a ChannelHandler is stateless, it can be marked as Sharable, so that the server can handle all client events by holding only one instance.
@Inherited
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Sharable {
}
Copy the code
As the default implementation of ChannelHandler, ChannelHandlerAdapter has an important method, isSharable(), which looks like this:
public boolean isSharable() { Class<? > clazz = this.getClass(); // Cache Map<Class<? >, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache(); Boolean sharable = (Boolean)cache.get(clazz); If (sharable = = null) {/ / Handler if there is a sharable annotation sharable = clazz. IsAnnotationPresent (sharable. Class); cache.put(clazz, sharable); } return sharable; }Copy the code
This introduces the optimized thread-local variable InternalThreadLocalMap, which means that each thread has a cache of whether ChannelHandler is Sharable. This reduces contention between threads and improves performance.
ChannelInboundHandler
ChannelInboundHandler handles inbound data and various state changes, and calls some lifecycle methods in ChannelInboundHandler when the state of a Channel changes. These methods are closely related to the life of the Channel.
Inbound data is the data that goes into the socket. Some of the lifecycle apis for this interface are shown below:
ChannelInboundHandlerAdapter as ChannelInboundHandler implementation, by default the inbound events will be automatically transmitted to the next inbound processor. The code is highly consistent, as follows:
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.fireChannelRead(msg);
}
Copy the code
ChannelOutboundHandler
Outbound operations and data are handled by ChannelOutboundHandler. Its methods will be called by Channel, ChannelPipeline, and ChannelHandlerContext. A powerful feature of ChannelOutboundHandler is the ability to defer operations or events as needed, which makes it possible to process requests in complex ways.
For example, if a write to a remote node is paused, you can postpone the flushing operation and continue later.
Similarly, ChannelOutboundHandlerAdapter as ChannelOutboundHandler events, the default will spread to the next outbound outbound event processor:
@Override
public void read(ChannelHandlerContext ctx) throws Exception {
ctx.read();
}
Copy the code
ChannelDuplexHandler
The ChannelDuplexHandler interface implements both ChannelInboundHandler and ChannelOutboundHandler interfaces. If a required ChannelHandler handles both inbound and outbound events, it is recommended to inherit this class.
conclusion
Above is about the analysis of ChannelHandler, I believe you have a certain understanding of ChannelHandler, next period we will analyze the source code of ChannelPipeline.