java shareable_netty(十九)ChannelInitializer 使用公共handler(@Shareable)实践及逻辑解答【重点】...

在 netty channel的线程安全性与@Sharable  中讨论了ChannelInitializer,Pipeline,@Shareable,本质就2点:

1)ChannelInitializer可以实现每个连接创建一个pipeline,而且pipeline内的handler,每个连接都能有个新的sethandler

这个地方会有过误解:其实不是你用了ChannelInitializer,就是每个连接都有一个新的handler了,你也可以在ChannelInitializer中设置一个公共对象(@Shareable修饰,意为:可共享的)

当然对于这样一个对象,书上说的不全准确,比起对象的线程安全性,更重要的是你得确定它是关于连接无状态的,比如StringDecoder,不能是LengthDecoder这样的

2)channel属于一个线程,ChannelPipeline属于一个channel,所以对ChannelPipeline的操作始终在一个线程内,可以随意remove add而不用考虑同一时刻,有另外一个线程在操作pipeline,因为对一个channel的操作,netty承诺始终在一个线程中

本文对第1)点,尝试一个案例,在netty粘包(一)消息定长 实践的代码基础上,使ChannelInitializer中的handler为同一对象

一 多个handler

ChannelHandler [] channelHandlers = {

new FixedLengthFrameDecoder(14),

new StringDecoder(),

new StringEncoder(),

new ServerHandler4(),

new ServerHandler5()

};

//设置管道工厂

bootstrap.childHandler(new ChannelInitializer() {

// 多个handler

@Override

protected void initChannel(SocketChannel socketChannel) throws Exception {

//获取管道

ChannelPipeline pipeline = socketChannel.pipeline();

//定长解码类

pipeline.addLast(channelHandlers[0]);

//字符串解码类

pipeline.addLast(channelHandlers[1]);

pipeline.addLast(channelHandlers[2]);

//处理类

pipeline.addLast(channelHandlers[3]);

pipeline.addLast(channelHandlers[4]);

}

});

二 单个handler

// 单个handler

bootstrap.childHandler(new SimpleChannelInboundHandler() {

@Override

protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {

System.out.println("Received data");

}

});

第一个client连接

a 单个handler输出

server start ......

Received data

与预期一致,单handler服务端沾包了,只打印了一条

b 多个handler按5条正常输出

当第二个client连接时

十二月 17, 2019 9:34:19 下午 io.netty.channel.ChannelInitializer channelRegistered

警告: Failed to initialize a channel. Closing: [id: 0x08956454, /127.0.0.1:58422 => /127.0.0.1:8866]

io.netty.channel.ChannelPipelineException: io.netty.handler.codec.FixedLengthFrameDecoder is not a @Sharable handler, so can't be added or removed multiple times.

at io.netty.channel.DefaultChannelPipeline.checkMultiplicity(DefaultChannelPipeline.java:461)

at io.netty.channel.DefaultChannelPipeline.addLast0(DefaultChannelPipeline.java:138)

at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:131)

at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:258)

at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:245)

at com.jds.test.stringlength.Server5$1.initChannel(Server5.java:47)

-=======-

十二月 17, 2019 10:10:26 下午 io.netty.channel.DefaultChannelPipeline$TailHandler exceptionCaught

警告: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.

io.netty.channel.ChannelPipelineException: com.jds.test.stringlength.Server6$1 is not a @Sharable handler, so can't be added or removed multiple times.

io.netty.handler.codec.FixedLengthFrameDecoder这是一个连接相关的handler,是不能共用的,每个连接应保持内部读取的字节状态以处理沾包,它不像StringDecoder和StringEncoder,连接无关,输入参byte数组,输出字符串,可以共用,事实上netty也将这两个ChannelHandlerAdapter声明为@Shareable

4657d345a6994bee217e15b6d87e65ee.png

e23c41e1ef85da738c3aeb8e46df9503.png

52cb217190d0c1fc06404ed9044e0116.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值