当前位置: 首页 > 工具软件 > BIE > 使用案例 >

关于netty的@Sharable注解含义,你可bie瞎说了

黄沈浪
2023-12-01

@Sharable的真实含义

1.当netty尝试往多个channel的pipeline中添加同一个ChannelHandlerAdapter实例时,会判断该实例类是否添加了@Sharable,没有则抛出... is not a @Sharable handler, so can't be added or removed multiple times异常

      如果你添加的不是单例Handler,你加不加@Sharable没有任何区别

      如果你添加的是单例Handler,只要它会被添加到多个channel的pipeline,那就必须加上@Sharable

2.网上有些资料说netty会将注解了@Sharable的Handler单例化,实在误导人。channelHandler是不是单例跟netty没有任何关系,netty只会在你尝试用单例ChannelHandler时加上第1条说明的限制,这个限制意思很明确,多个channel公用单例ChannelHandler,那它就必须是线程安全的,@Sharable就是用于告诉netty,我这个Handler是线程安全的,可以被多个channel安全的share,假如你搞了个线程不安全的类,你对它用上了单例,还加个@Sharable,这时候netty拿你也没办法,只是你的老板可能会有点不开心

一般情况下,我们的代码是这样:

bootstrap.childHandler(new ChannelInitializer<Channel>() {

      @Override

      protected void initChannel(Channel ch) throws Exception {

            ch.pipeline().addLast(new ShareTestChannelHandler());

      };

});

在initChannel方法中,我们addLast传入的Handler实例,他是不是单例的与netty没有任何关系和你是否注解@Sharable也没有任何关系

就拿上面的代码说,它就不是单例的,每次都是new一个新对象,这时候你加不加@Sharable没有任何区别

如果,你传入一个单例的Handler对象,只要它会被添加到多个channel的pipeline链中,那它就必须是@Sharable的,不然就抛出第1点说的异常:

bootstrap.childHandler(new ChannelInitializer<Channel>() {

      @Override

      protected void initChannel(Channel ch) throws Exception {

            ch.pipeline().addLast(ShareTestChannelHandler.INSTANCE);

      };

});

@Sharable

public class ShareTestChannelHandler extends SimpleChannelInboundHandler<ByteBuf>

      public static ShareTestChannelHandler INSTANCE = new ShareTestChannelHandler();

      private ShareTestChannelHandler() {}

      ......

}

那是不是所有Handler都可以加上@Sharable呢?

不是,netty中,解码器有关的Handler都是不安全的,因为粘包拆包的缘故,Decoder必须要保存一些解析过程的中间状态,比如ByteToMessageDecoder类中维护的一个字节累加器cumulation,每次读到当前channel的消息后都会将消息累加到cumulation中,然后再调用子类实现的decode方法。

所以它不能被多个channel安全的共享,netty明确的禁止了使用单例Decoder,即使你自作聪明的给他加上@Sharable,也会被禁止掉,抛出... is not allowed to be shared错误,所以我们在添加Decoder时,1必须不是单例,2不要添加@Sharable

 类似资料: