public interface ChannelHandler
ChannelInboundInvoker or ChannelOutboundInvoker operation, and forwards it
 to the next handler in a ChannelPipeline.
 
 ChannelHandler itself does not provide many methods.  To handle a
 a ChannelInboundInvoker or ChannelOutboundInvoker operation
 you need to implement its sub-interfaces.  There are many different sub-interfaces
 which handles inbound and outbound operations.
 But the most useful for developers may be:
 
ChannelInboundHandlerAdapter handles and intercepts inbound operationsChannelOutboundHandlerAdapter handles and intercepts outbound operations
 A ChannelHandler is provided with a ChannelHandlerContext
 object.  A ChannelHandler is supposed to interact with the
 ChannelPipeline it belongs to via a context object.  Using the
 context object, the ChannelHandler can pass events upstream or
 downstream, modify the pipeline dynamically, or store the information
  (using AttributeKeys) which is specific to the handler.
 
ChannelHandler often needs to store some stateful information.
 The simplest and recommended approach is to use member variables:
 
 public interface Message {
     // your methods here
 }
 public class DataServerHandler extends SimpleChannelInboundHandler<Message> {
     private boolean loggedIn;
     @Override
     public void channelRead0(ChannelHandlerContext ctx, Message message) {
         Channel ch = e.getChannel();
         if (message instanceof LoginMessage) {
             authenticate((LoginMessage) message);
             loggedIn = true;
         } else (message instanceof GetDataMessage) {
             if (loggedIn) {
                 ch.write(fetchSecret((GetDataMessage) message));
             } else {
                 fail();
             }
         }
     }
     ...
 }
 
 Because the handler instance has a state variable which is dedicated to
 one connection, you have to create a new handler instance for each new
 channel to avoid a race condition where a unauthenticated client can get
 the confidential information:
 // Create a new handler instance per channel. // SeeChannelInitializer.initChannel(Channel). public class DataServerInitializer extendsChannelInitializer<Channel> {@Overridepublic void initChannel(Channelchannel) { channel.pipeline().addLast("handler", new DataServerHandler()); } }
AttributeKeyAttributeKeys which is provided by
 ChannelHandlerContext:
 
 public interface Message {
     // your methods here
 }
 @Sharable
 public class DataServerHandler extends SimpleChannelInboundHandler<Message> {
     private final AttributeKey<Boolean> auth =
           AttributeKey.valueOf("auth");
     @Override
     public void channelRead(ChannelHandlerContext ctx, Message message) {
         Attribute<Boolean> attr = ctx.attr(auth);
         Channel ch = ctx.channel();
         if (message instanceof LoginMessage) {
             authenticate((LoginMessage) o);
             attr.set(true);
         } else (message instanceof GetDataMessage) {
             if (Boolean.TRUE.equals(attr.get())) {
                 ch.write(fetchSecret((GetDataMessage) o));
             } else {
                 fail();
             }
         }
     }
     ...
 }
 
 Now that the state of the handler isattached to the ChannelHandlerContext, you can add the
 same handler instance to different pipelines:
 public class DataServerInitializer extendsChannelInitializer<Channel> { private static final DataServerHandler SHARED = new DataServerHandler();@Overridepublic void initChannel(Channelchannel) { channel.pipeline().addLast("handler", SHARED); } }
@Sharable annotation
 In the example above which used an AttributeKey,
 you might have noticed the @Sharable annotation.
 
 If a ChannelHandler is annotated with the @Sharable
 annotation, it means you can create an instance of the handler just once and
 add it to one or more ChannelPipelines multiple times without
 a race condition.
 
If this annotation is not specified, you have to create a new handler instance every time you add it to a pipeline because it has unshared state such as member variables.
This annotation is provided for documentation purpose, just like the JCIP annotations.
 Please refer to the ChannelHandler, and
 ChannelPipeline to find out more about inbound and outbound operations,
 what fundamental differences they have, how they flow in a  pipeline,  and how to handle
 the operation in your application.
| 限定符和类型 | 接口和说明 | 
|---|---|
static interface  | 
ChannelHandler.Sharable
Indicates that the same instance of the annotated  
ChannelHandler
 can be added to one or more ChannelPipelines multiple times
 without a race condition. | 
| 限定符和类型 | 方法和说明 | 
|---|---|
void | 
exceptionCaught(ChannelHandlerContext ctx,
               java.lang.Throwable cause)
已过时。 
 
is part of  
ChannelInboundHandler | 
void | 
handlerAdded(ChannelHandlerContext ctx)
Gets called after the  
ChannelHandler was added to the actual context and it's ready to handle events. | 
void | 
handlerRemoved(ChannelHandlerContext ctx)
Gets called after the  
ChannelHandler was removed from the actual context and it doesn't handle events
 anymore. | 
void handlerAdded(ChannelHandlerContext ctx) throws java.lang.Exception
ChannelHandler was added to the actual context and it's ready to handle events.java.lang.Exceptionvoid handlerRemoved(ChannelHandlerContext ctx) throws java.lang.Exception
ChannelHandler was removed from the actual context and it doesn't handle events
 anymore.java.lang.Exception@Deprecated void exceptionCaught(ChannelHandlerContext ctx, java.lang.Throwable cause) throws java.lang.Exception
ChannelInboundHandlerThrowable was thrown.java.lang.Exception