Netty ChannelHandler使用报错

点击量:2931

最近在研究和学习Netty,按照书上的教程写了一个很简单的demo,但是运行却报错了,代码如下:

启动好了之后,浏览器输入:http://127.0.0.1:7777?x=1&y=2 ,但是令人奇怪的是这个服务器只能接受一次请求,后面的请求均会产生如下的报错:

按照报错的提示,原因就是这个channelHandler没有使用@Shareable注解,加上之后果然问题解决了。但是到这里我的疑问并没有得到解决,为什么这个handler必须要加上@Shareable注解?这一步步到底是怎么回事?经过几次断点,再结合阅读源码,总算是搞清楚为什么了。
首先来看抛出异常的方法DefaultChannelPipeline->checkMultiplicity,代码如下:

这段代码很简单,如果这个handler被加过了,也就是h.adder=true,并且不是shareable的,就会抛出异常。但是为很么会重复加呢?
再来看ServerBootstrap.java 第232行:

我们可以发现每当有新的数据可读时都会往这个channel的pipeline里加入handler,这里加的是childHander。值得注意的是,我们初始化的时候这个childHandler都是同一个实例,也就说会导致不同的channel用了同一个handler,这个从netty的设计角度来说是要避免的。因为netty的一大好处就是每一个channel都有自己绑定的eventloop和channelHandler,这样可以保证代码串行执行,不必考虑并发同步的问题。所以才会有checkMultiplicity这个方法来检查这个问题。那该怎么办呢?netty的这段代码:child.pipeline().addLast(childHandler)就是用了同一个handler啊,怎么才能为每一个channel创建不同的handler呢?
很简单,只要写个类继承ChannelInitializer就行了,ChannelInitializer这个类比较特殊,你可以把它想象成是很多channelhandler的集合体,而且这个类就是@Shareable的,继承了这个类之后你可以为每一个channel单独创建handler,甚至是多个handler。

和之前那个handler一样,虽然所有的channel都共享了ChannelInitializerImpl这个实例,但是这个实例却能为每一个channel new出新的handler实例,这就是区别。

发表评论

电子邮件地址不会被公开。 必填项已用*标注