org.jboss.netty.channel
接口 ChannelHandler

所有已知子接口:
ChannelDownstreamHandler, ChannelUpstreamHandler, LifeCycleAwareChannelHandler
所有已知实现类:
Base64Decoder, Base64Encoder, BlockingReadHandler, BufferedWriteHandler, ChunkedWriteHandler, CompatibleObjectDecoder, CompatibleObjectEncoder, DelimiterBasedFrameDecoder, ExecutionHandler, FixedLengthFrameDecoder, FrameDecoder, HttpChunkAggregator, HttpClientCodec, HttpContentCompressor, HttpContentDecoder, HttpContentDecompressor, HttpContentEncoder, HttpMessageDecoder, HttpMessageEncoder, HttpRequestDecoder, HttpRequestEncoder, HttpResponseDecoder, HttpResponseEncoder, HttpServerCodec, IdleStateAwareChannelHandler, IdleStateAwareChannelUpstreamHandler, IdleStateHandler, LengthFieldBasedFrameDecoder, LengthFieldPrepender, LoggingHandler, ObjectDecoder, ObjectEncoder, OneToOneDecoder, OneToOneEncoder, ProtobufDecoder, ProtobufEncoder, ProtobufVarint32FrameDecoder, ProtobufVarint32LengthFieldPrepender, ReadTimeoutHandler, ReplayingDecoder, RtspMessageDecoder, RtspMessageEncoder, RtspRequestDecoder, RtspRequestEncoder, RtspResponseDecoder, RtspResponseEncoder, SimpleChannelDownstreamHandler, SimpleChannelHandler, SimpleChannelUpstreamHandler, SslHandler, StringDecoder, StringEncoder, WebSocketFrameDecoder, WebSocketFrameEncoder, WriteTimeoutHandler, ZlibDecoder, ZlibEncoder

public interface ChannelHandler

处理或拦截一个ChannelEvent并发送一个 ChannelEventChannelPipeline 里的下一个处理器 .

子类

ChannelHandler自己并不提供任何方法.要处理一个ChannelEvent ,你需要实现它的子接口.它有两个处理收到事件的子接口,一个用于上游事件,另一个用于下游事件:

你也可以通过每个子接口的文档里了解更多关于如何拦截一个上游和下游的事件.

上下文对象

一个ChannelHandler是通过ChannelHandlerContext对象提供的.一个 ChannelHandler应该通过一个上下文和他属于的ChannelPipeline交互.使用上下文对象, ChannelHandler可以传递上游事件或下游事件、动态修改管道,或保存信息(附件)到指定的处理器中.

状态管理

一个ChannelHandler经常需要保存一下有状态的信息.最简单和推荐的方法是使用成员变量:
 public class DataServerHandler extends SimpleChannelHandler {
 
     private boolean loggedIn;
 
     @Override
     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
         Channel ch = e.getChannel();
         Object o = e.getMessage();
         if (o instanceof LoginMessage) {
             authenticate((LoginMessage) o);
             loggedIn = true;
         } else (o instanceof GetDataMessage) {
             if (loggedIn) {
                 ch.write(fetchSecret((GetDataMessage) o));
             } else {
                 fail();
             }
         }
     }
     ...
 }
 
由于处理器实例有一个专用于一个连接的状态变量,所以你需要为每个新的通道创建一个新的处理器实例以避免一个非法客户端获取机密信息的条件竞争:
 // 为每个通道创建一个处理器实例.
 // 查看Bootstrap.setPipelineFactory(ChannelPipelineFactory).
 public class DataServerPipelineFactory implements ChannelPipelineFactory {
     public ChannelPipeline getPipeline() {
         return Channels.pipeline(new DataServerHandler());
     }
 }
 

使用一个附件

尽管建议使用成员变量保存一个处理器的状态,但由于很多原因你不能创建很多处理器实例.在这种情况下,你可以使用 ChannelHandlerContext提供的附件:
 @Sharable
 public class DataServerHandler extends SimpleChannelHandler {
 
     @Override
     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
         Channel ch = e.getChannel();
         Object o = e.getMessage();
         if (o instanceof LoginMessage) {
             authenticate((LoginMessage) o);
             ctx.setAttachment(true);
         } else (o instanceof GetDataMessage) {
             if (Boolean.TRUE.equals(ctx.getAttachment())) {
                 ch.write(fetchSecret((GetDataMessage) o));
             } else {
                 fail();
             }
         }
     }
     ...
 }
 
既然使用附件保存处理器的状态,你可以为不同的管道添加相同的处理器实例:
 public class DataServerPipelineFactory implements ChannelPipelineFactory {
 
     private static final DataServerHandler SHARED = new DataServerHandler();
 
     public ChannelPipeline getPipeline() {
         return Channels.pipeline(SHARED);
     }
 }
 

使用ChannelLocal

如果你有一个状态变量需要被其他处理器或外部处理器访问,你可以使用ChannelLocal:
 public final class DataServerState {
 
     public static final ChannelLocal<Boolean> loggedIn = new ChannelLocal<Boolean>() {
         protected Boolean initialValue(Channel channel) {
             return false;
         }
     }
     ...
 }
 
 @Sharable
 public class DataServerHandler extends SimpleChannelHandler {
 
     @Override
     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
         Channel ch = e.getChannel();
         Object o = e.getMessage();
         if (o instanceof LoginMessage) {
             authenticate((LoginMessage) o);
             DataServerState.loggedIn.set(ch, true);
         } else (o instanceof GetDataMessage) {
             if (DataServerState.loggedIn.get(ch)) {
                 ctx.getChannel().write(fetchSecret((GetDataMessage) o));
             } else {
                 fail();
             }
         }
     }
     ...
 }
 
 // 打印合法客户端的远程地址:
 ChannelGroup allClientChannels = ...;
 for (Channel ch: allClientChannels) {
     if (DataServerState.loggedIn.get(ch)) {
         System.out.println(ch.getRemoteAddress());
     }
 }
 

@Sharable注解

不管上面例子是使用附件还是ChannelLocal,你可以注意到@Sharable注解.

如果一个ChannelHandler使用@Sharable 注解,这意味着你可以只创建一次处理器实例,并可以多次添加到一个或多个ChannelPipeline上而不会发生条件竞争.

如果没有指定该注解,你必须每次创建一个新的处理器实例并添加到一个管道上,因为它有不共享的状态,如成员变量.

该注解被作为文档目的提供,就像 JCIP注解.

其他值得一读的资源

查阅ChannelEventChannelPipeline了解什么是上游事件和下游事件,它们的区别以及如果在管道中流动.


嵌套类摘要
static interface ChannelHandler.Sharable
          表示被注解的相同ChannelHandler实例可以被多次添加到一个或多个ChannelPipeline 上而不会发生条件竞争.