Netty中ChannelHandler共享数据的方式

(一)成员变量

public class DataServerHandler extends SimpleChannelHandler {
    // 成员变量
    private boolean loggedIn;

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        ...
    }
}
  • 如果只是想在当前连接内共享数据,那么需要针对不同的Channel创建不同的ChannelHandler实例,避免共享范围扩大至所有连接。
// 所有Channel共用一个ChannelHandler实例 
public class DataServerPipelineFactory implements ChannelPipelineFactory {

     private static final DataServerHandler SHARED = new DataServerHandler();

     public ChannelPipeline getPipeline() {
         return Channels.pipeline(SHARED);
     }
 }
// 每一个Channel创建一个ChannelHandler实例
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
    public ChannelPipeline getPipeline() {
        ChannelPipeline pipeline = pipeline();      
        pipeline.addLast("handler", new TestHandler());
        return pipeline;
    }
});

(二)ChannelHandlerContext

  • ChannelHandlerContext是在Pipline注册ChannelHandler的时候和其绑定的,因此一个被多次注册(无论是否是同一个Pipline)的ChannelHandler会同时拥有多个ChannelHandlerContext。
  • 对于ChannelHandlerContext一个常见的误解是以为其可以在同一个Pipline的各个Handler之间传递数据。如果真要这样做,应该使用MessageEvent或者ChannelLocal。
@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);
        }
    }
}
  • @Sharable注解只是起到一个标示的作用,说明一个该ChannelHandler实例可以被多次注册到一个或者多个Pipline中,而且不会导致不同的Channel共享数据出现竞争条件。
  • 基于ChannelHandlerContext同ChannelHandler的绑定时机和机制,很容易理解在本例中是怎么保证@Sharable的。

(三)Channel

  • 该方法类似ChannelLocal,只是共享数据是直接存储在Channel实例中的。
@Sharable
public class TestHandler extends SimpleChannelHandler {
    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) throws Exception {
        // 通过任意一种方式获取到当前Channel,然后设置共享数据
        ctx.getChannel().setAttachment(true);
        event.getChannel().setAttachment(true);
    }
}
  • 很明显,本例中的ChannelLocal也是符合@Sharable要求的。

(四)ChannelLocal

  • 如果想在当前连接的其他ChannelHandler或者外部Handler中共享数据,则可以使用ChannelLocal。其设计思想类似于JDK中的ThreadLocal,其内部是一个Channel做Key,共享数据做Value的结构。
public final class DataServerState {

    public static final ChannelLocal<Boolean> loggedIn = new ChannelLocal<>() {
        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);
        }
    }
}
  • 很明显,本例中的ChannelLocal也是符合@Sharable要求的。
  • 14
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值