日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Netty @Sharable的使用

發(fā)布時(shí)間:2025/3/15 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Netty @Sharable的使用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、@Sharable的真實(shí)含義

  • 當(dāng)netty嘗試往多個(gè)channel的pipeline中添加同一個(gè)ChannelHandlerAdapter實(shí)例時(shí),會判斷該實(shí)例類是否添加了@Sharable,沒有則拋出… is not a @Sharable handler, so can’t be added or removed multiple times異常
  • 如果你添加的不是單例Handler,你加不加@Sharable沒有任何區(qū)別

  • 如果你添加的是單例Handler,只要它會被添加到多個(gè)channel的pipeline,那就必須加上@Sharable

  • 網(wǎng)上有些資料說netty會將注解了@Sharable的Handler單例化,實(shí)在誤導(dǎo)人。channelHandler是不是單例跟netty沒有任何關(guān)系,netty只會在你嘗試用單例ChannelHandler時(shí)加上第1條說明的限制,這個(gè)限制意思很明確,多個(gè)channel公用單例ChannelHandler,那它就必須是線程安全的,@Sharable就是用于告訴netty,我這個(gè)Handler是線程安全的,可以被多個(gè)channel安全的share,假如你搞了個(gè)線程不安全的類,你對它用上了單例,還加個(gè)@Sharable,這時(shí)候netty拿你也沒辦法,只是你的老板可能會有點(diǎn)不開心
    • 一般情況下,我們的代碼是這樣:
    bootstrap.childHandler(new ChannelInitializer<Channel>() {@Overrideprotected void initChannel(Channel ch) throws Exception {//每次都是new一個(gè)新對象,這時(shí)候你 ShareTestChannelHandler這個(gè)類加不加@Sharable沒有任何區(qū)別ch.pipeline().addLast(new ShareTestChannelHandler());}; });

    在initChannel方法中,我們addLast傳入的Handler實(shí)例,他是不是單例的與netty沒有任何關(guān)系,和你是否注解@Sharable也沒有任何關(guān)系。就拿上面的代碼說,它就不是單例的,每次都是new一個(gè)新對象,這時(shí)候你ShareTestChannelHandler這個(gè)類加不加@Sharable沒有任何區(qū)別。

    • 如下代碼
    bootstrap.childHandler(new ChannelInitializer<Channel>() {@Overrideprotected void initChannel(Channel ch) throws Exception {//每次傳入的都是單例的Handler對象,只要它會被添加到多個(gè)channel的pipeline鏈中,那它就必須是@Sharable的,不然就拋出第1點(diǎn)說的異常ch.pipeline().addLast(new ShareTestChannelHandler());}; });@Sharable public class ShareTestChannelHandler extends SimpleChannelInboundHandler<ByteBuf>public static ShareTestChannelHandler INSTANCE = new ShareTestChannelHandler();private ShareTestChannelHandler() {}...... }

    如果,你傳入一個(gè)單例的Handler對象,只要它會被添加到多個(gè)channel的pipeline鏈中,那它就必須是@Sharable的,不然就拋出第1點(diǎn)說的異常

    二、是不是所有Handler都可以加上@Sharable

  • 不是,netty中,解碼器有關(guān)的Handler都是不安全的,因?yàn)檎嘲鸢木壒?#xff0c;Decoder必須要保存一些解析過程的中間狀態(tài),比如ByteToMessageDecoder類中維護(hù)的一個(gè)字節(jié)累加器cumulation,每次讀到當(dāng)前channel的消息后都會將消息累加到cumulation中,然后再調(diào)用子類實(shí)現(xiàn)的decode方法。所以它不能被多個(gè)channel安全的共享,netty明確的禁止了使用單例Decoder,即使你自作聰明的給他加上@Sharable,也會被禁止掉,拋出... is not allowed to be shared錯(cuò)誤。
  • 所以我們在添加Decoder時(shí):
  • 必須不是單例
  • 不要添加@Sharable
  • 例子
  • @Slf4j //這里添加了@Sharable,肯定會報(bào)錯(cuò) @ChannelHandler.Sharable public class MessageCodec extends ByteToMessageCodec<Message> {@Overridepublic void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {// 1. 4 字節(jié)的魔數(shù)out.writeBytes(new byte[]{1, 2, 3, 4});// 2. 1 字節(jié)的版本,out.writeByte(1);// 3. 1 字節(jié)的序列化方式 jdk 0 , json 1out.writeByte(0);// 4. 1 字節(jié)的指令類型out.writeByte(msg.getMessageType());// 5. 4 個(gè)字節(jié)out.writeInt(msg.getSequenceId());// 無意義,對齊填充,讓固定字節(jié)數(shù)為2的n次方倍out.writeByte(0xff);// 6. 獲取內(nèi)容的字節(jié)數(shù)組(序列化)ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(msg);byte[] bytes = bos.toByteArray();// 7. 長度out.writeInt(bytes.length);// 8. 寫入內(nèi)容out.writeBytes(bytes);}@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {int magicNum = in.readInt();byte version = in.readByte();byte serializerType = in.readByte();byte messageType = in.readByte();int sequenceId = in.readInt();in.readByte();int length = in.readInt();byte[] bytes = new byte[length];in.readBytes(bytes, 0, length);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));Message message = (Message) ois.readObject();log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);log.debug("{}", message);//可能解析出多條信息,加到list里面,給下一個(gè)handler處理out.add(message);} }

    但是,如果我們明確知道MessageCodec是線程安全的),要使用@Sharable,就不要繼承ByteToMessageCodec了,可以通過繼承 MessageToMessageCodec來實(shí)現(xiàn)。

    @Slf4j @ChannelHandler.Sharable /*** 必須和 LengthFieldBasedFrameDecoder 一起使用,以確保接到的 ByteBuf 消息是完整的,防止沒接收到完整信息,又切換到其他channel使用,導(dǎo)致線程不安全*/ public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {@Overridepublic void encode(ChannelHandlerContext ctx, Message msg, List<Object> outList) throws Exception {ByteBuf out = ctx.alloc().buffer();// 1. 4 字節(jié)的魔數(shù)out.writeBytes(new byte[]{1, 2, 3, 4});// 2. 1 字節(jié)的版本,out.writeByte(1);// 3. 1 字節(jié)的序列化方式 jdk 0 , json 1out.writeByte(Config.getSerializerAlgorithm().ordinal());// 4. 1 字節(jié)的指令類型out.writeByte(msg.getMessageType());// 5. 4 個(gè)字節(jié)out.writeInt(msg.getSequenceId());// 無意義,對齊填充out.writeByte(0xff);// 6. 獲取內(nèi)容的字節(jié)數(shù)組byte[] bytes = Config.getSerializerAlgorithm().serialize(msg);// 7. 長度out.writeInt(bytes.length);// 8. 寫入內(nèi)容out.writeBytes(bytes);outList.add(out);}@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {int magicNum = in.readInt();byte version = in.readByte();byte serializerAlgorithm = in.readByte(); // 0 或 1byte messageType = in.readByte(); // 0,1,2...int sequenceId = in.readInt();in.readByte();int length = in.readInt();byte[] bytes = new byte[length];in.readBytes(bytes, 0, length);// 找到反序列化算法Serializer.Algorithm algorithm = Serializer.Algorithm.values()[serializerAlgorithm];// 確定具體消息類型Class<? extends Message> messageClass = Message.getMessageClass(messageType);Message message = algorithm.deserialize(messageClass, bytes);out.add(message);} }

    三、總結(jié)

    加了@Sharable的類,netty就認(rèn)為是線程安全,可以共享,而只要netty明確的禁止了使用單例Handler,即使你給他加上@Sharable,也會被禁止掉。同時(shí),如果一個(gè)類是單例的Handler對象,同時(shí)他會被添加到多個(gè)channel的pipeline鏈中,那它就必須是@Sharable的,不然也會報(bào)錯(cuò)。

    • handler 不保存狀態(tài)時(shí),就可以安全地在多線程下被共享
    • 但要注意對于編解碼器類,不能繼承 ByteToMessageCodec 或 CombinedChannelDuplexHandler 父類,他們的構(gòu)造方法對 @Sharable 有限制
    • 如果能確保編解碼器不會保存狀態(tài),可以繼承 MessageToMessageCodec 父類

    參考視頻
    參考文章
    參考文章

    總結(jié)

    以上是生活随笔為你收集整理的Netty @Sharable的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。