1.背景
熟悉Netty的人都了解,netty为每个连接的客户端都会创建一个channel用于通信相关。每个channel都绑定到一条channelpipeline上。而channelpipeline里由一个一个的节点channelhandler组成(严格来说是channelhandlercontext)。如果为所有channel都实例化各个channelhandler的话,那对于内存还是性能来说无疑是浪费的。
因此, @Shareable注解应运而生。
2.@Shareable注解说明
@Shareable注解的handler能够被多个ChannelPipeline公用。能够被标记的handler必须是无状态的,例如没有成员变量(成员变量是线程私有的除外)。源代码的注释如下:
/*** Indicates that the same instance of the annotated {@link ChannelHandler}* can be added to one or more {@link ChannelPipeline}s multiple times* without a race condition.* <p>* If this annotation is not specified, you have to create a new handler* instance every time you add it to a pipeline because it has unshared* state such as member variables.* <p>* This annotation is provided for documentation purpose, just like* <a href="http://www.javaconcurrencyinpractice.com/annotations/doc/">the JCIP annotations</a>.*/@Inherited@Documented@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@interface Sharable {// no value}
如果你自定义的一个channelhandler希望实现在所有channelpipeline共享,那就可以加上@Shareable注解。
3.@Shareable注解使用限制
需要注意的是,不是所有的handler都可以添加这个注解的,被修饰的handler必须是无状态的,或者说,线程安全的。例如,如果解码器继承自ByteToMessageDecoder,就不能添加该注解。因为ByteToMessageDecoder类里含有成员变量。
如果ByteToMessageDecoder的子类不小心加上该注解,则在实例化的时候会报异常(java.lang.IllegalStateException: ChannelHandler XXX is not allowed to be shared),代码如下:
4. @Shareable注解的正确使用姿势
即使channelhandler是无状态的,申明@Shareable注解之后,也应该保证handler是单例的,不然无法生效。例如jforgame的NSocketServer
如果未标注@Shareable注解,但客户端代码不小心把它当成单例使用,则在运行期会出现异常。