实践Netty深入解析

ChannelInitializer

@Sharable

默认ChannelHandler实例是不能被复用的(防止多线程安全问题),如果需要复用,则需要多实例或者@Sharable(某些ChannelHandler不可以Sharable)

1
io.netty.channel.ChannelPipelineException: com.allinpay.its.tg.protocol.socket.AsciiLengthFieldBasedFrameDecoder is not a @Sharable handler, so can't be added or removed multiple times.   at io.netty.channel.DefaultChannelPipeline.checkMultiplicity(DefaultChannelPipeline.java:524) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelPipeline.addLast0(DefaultChannelPipeline.java:153) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:146) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:300) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:282) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at com.allinpay.its.tg.protocol.socket.ServerChannelHandlerInitializer.initChannel(ServerChannelHandlerInitializer.java:34) ~[classes/:na]   at com.allinpay.its.tg.protocol.socket.ServerChannelHandlerInitializer.initChannel(ServerChannelHandlerInitializer.java:1) ~[classes/:na]   at io.netty.channel.ChannelInitializer.channelRegistered(ChannelInitializer.java:69) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelRegisteredNow(ChannelHandlerInvokerUtil.java:30) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRegistered(DefaultChannelHandlerInvoker.java:49) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelHandlerContext.fireChannelRegistered(DefaultChannelHandlerContext.java:285) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.ChannelInitializer.channelRegistered(ChannelInitializer.java:71) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelRegisteredNow(ChannelHandlerInvokerUtil.java:30) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRegistered(DefaultChannelHandlerInvoker.java:49) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelHandlerContext.fireChannelRegistered(DefaultChannelHandlerContext.java:285) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.DefaultChannelPipeline.fireChannelRegistered(DefaultChannelPipeline.java:801) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:427) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.AbstractChannel$AbstractUnsafe.access$100(AbstractChannel.java:369) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:403) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:318) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:353) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:794) [netty-all-5.0.0.Alpha1.jar:5.0.0.Alpha1]   at java.lang.Thread.run(Thread.java:662) [na:1.6.0_38] 2015-11-21 12:07:12.125 INFO [nioEventLoopGroup-3-2] com.allinpay.its.tg.protocol.socket.SocketServer:88 >>连接被关闭:127.0.0.1:51337 -> 0.0.0.0:8091

AsciiLengthFieldBasedFrameDecoder添加@Sharable后,报错如下:

1
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'socketServer1' defined in file [D:\Workspace\backup\its-core\target\classes\META-INF\spring\socket-server-context.xml]: Cannot resolve reference to bean 'serverChannelHandlerInitializer' while setting bean property 'serverChannelHandlerInitializer'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverChannelHandlerInitializer' defined in file [D:\Workspace\backup\its-core\target\classes\META-INF\spring\socket-server-context.xml]: Cannot resolve reference to bean 'asciiLengthFieldBasedFrameDecoder' while setting bean property 'asciilengthFieldBasedFrameDecoder'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'asciiLengthFieldBasedFrameDecoder' defined in file [D:\Workspace\backup\its-core\target\classes\META-INF\spring\socket-server-context.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.allinpay.its.tg.protocol.socket.AsciiLengthFieldBasedFrameDecoder]: Constructor threw exception; nested exception is java.lang.IllegalStateException: @Sharable annotation is not allowed   at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)   at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1391)   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1132)   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)   at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)   at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)   at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)   at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)   at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)   at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)   at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)   at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)   at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)   at com.allinpay.its.tg.bootstrap.Main.main(Main.java:14) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverChannelHandlerInitializer' defined in file [D:\Workspace\backup\its-core\target\classes\META-INF\spring\socket-server-context.xml]: Cannot resolve reference to bean 'asciiLengthFieldBasedFrameDecoder' while setting bean property 'asciilengthFieldBasedFrameDecoder'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'asciiLengthFieldBasedFrameDecoder' defined in file [D:\Workspace\backup\its-core\target\classes\META-INF\spring\socket-server-context.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.allinpay.its.tg.protocol.socket.AsciiLengthFieldBasedFrameDecoder]: Constructor threw exception; nested exception is java.lang.IllegalStateException: @Sharable annotation is not allowed   at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)   at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)

是因为ByteToMessageDecoder不允许@Sharable

1
2
3
protected ByteToMessageDecoder() {
    ensureNotSharable();
}

This annotation is provided for documentation purpose, just like the JCIP annotations(http://www.javaconcurrencyinpractice.com/annotations/doc/).

标记为@Sharable一定要确保没有多线程安全问题