netty源码学习 ChannelHandler(一)

channelHandler

channelHandler

自己本来没有很多方法,但是你通常必须实现其中一个子类型。

  1. ChannelInboundHandler 通常用处理入站(inbound)的IO事件类型
  2. ChannelOutboundHandler 通常用处理出站(outbound)的IO事件类型

另外,下边的一些适配器类,给你提供了便利。

  1. ChannelInboundHandlerAdapter 通常用处理入站的IO事件类型
  2. ChannelOutboundHandlerAdapter 通常用处理出站的IO事件类型
  3. ChannelDuplexHandler 同时处理进入和出去的事件处理器

The context object

ChannelHandler 提供了一个ChannelHandlerContext对象,
ChannelHandler应该通过上下文对象(context object)与它所属的ChannelPipeline进行交互。ChannelHandler可以通过事件upstream和downstream,使用这个上下文对象(context object)动态的修改pipeline或者使用AttributeKey存储每个handler的特殊信息。

一个channelHandler 通常需要存储一些有状态的(stateful)信息。最简单和推荐的方法是使用成员变量

public interface Message {
       // your methods here
   }
  
public class DataServerHandler extends SimpleChannelInboundHandler<Message> {
  
      private boolean loggedIn;
  
        @Override
      public void channelRead0(ChannelHandlerContext ctx, Message message) {
          if (message instanceof LoginMessage) {
               authenticate((LoginMessage) message);
               loggedIn = true;
           } else (message instanceof GetDataMessage) {
              if (loggedIn) {
                   ctx.writeAndFlush(fetchSecret((GetDataMessage) message));
               } else {
                   fail();
               }
           }
       }
       ...
   }

由于处理程序实例有一个专用于一个连接的状态变量,因此必须为每个新通道创建一个新的处理程序实例,以避免未经身份验证的客户端可以获取机密信息的竞争条件:

// Create a new handler instance per channel.
   // See ChannelInitializer.initChannel(Channel).
   public class DataServerInitializer extends ChannelInitializer<Channel> {
        @Override
       public void initChannel(Channel channel) {
           channel.pipeline().addLast("handler", new DataServerHandler());
       }
   }

注:A、B连个用户都与netty服务器建立连接。因为DataServerHandler声明loggedIn全局变量,为了防止冲突。每个channelPipeline通道都需要创建一个DataServerHandler对象,用来标记连接通道的用户是否登录。所以DataServerHandler不能共享(Sharable)。

使用 AttributeKey

尽管建议使用成员变量来存储处理程序的状态,但出于某些原因,您可能不想创建许多处理程序实例。在这种情况下,可以使用ChannelHandlerContext提供的AttributeKeys:

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);
           if (message instanceof LoginMessage) {
               authenticate((LoginMessage) o);
               attr.set(true);
           } else (message instanceof GetDataMessage) {
               if (Boolean.TRUE.equals(attr.get())) {
                   ctx.writeAndFlush(fetchSecret((GetDataMessage) o));
               } else {
                   fail();
               }
           }
       }
       ...
   }

既然处理程序的状态已附加到ChannelHandlerContext,那么可以将同一处理程序实例添加到不同的管道中

public class DataServerInitializer extends ChannelInitializer<Channel> {
  
       private static final DataServerHandler SHARED = new DataServerHandler();
  
        @Override
       public void initChannel(Channel channel) {
           channel.pipeline().addLast("handler", SHARED);
       }
   }

注:多个ChannelPipeline可以共享的变量,底层 看 AtomicReferenceArray : Object[] array = new Object[];
每个特殊元素的key,计算出所在的位置。DefaultAttributeMap.attr 方法添加元素

private static int index(AttributeKey<?> key) {
        return key.id() & MASK;
    }

@Sharable 注解

在上面使用AttributeKey的示例中,您可能注意到了@Sharable注释。
如果ChannelHandler使用@Sharable注释进行了注释,这意味着您可以只创建一次处理程序的实例,然后将其多次添加到一个或多个ChannelPipelines中,而不需要竞争条件。
如果未指定此注释,则每次将其添加到管道时都必须创建一个新的处理程序实例,因为它具有非共享状态(如成员变量)。
与JCIP注释一样,此注释是为文档目的而提供的。
其他值得一读的资源
请参阅ChannelHandler和ChannelPipeline以了解有关入站和出站操作的更多信息,它们有哪些基本区别,它们如何在管道中流动,以及如何在应用程序中处理操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值