今天我们来做一个优化,即实现消息处理器的复用,注意这里的复用,不是指同一个消息处理器在消息的客户端和服务端进行复用,而是指在多个消息通道中复用。
回顾下我们消息处理器装配的过程,代码实现如下:
/** * 初始化channel */ @Override public void initChannel(SocketChannel socketChannel) throws Exception { //获取通道链路 ChannelPipeline pipeline = socketChannel.pipeline(); 部分代码略…… //HTTP 编解码 pipeline.addLast(new HttpServerCodec()); //聚合HTTP 请求或响应 pipeline.addLast(new HttpObjectAggregator(64 * 1024)); //添加读写通道空闲处理器,当超时时,会触发userEventTrigger,由下个处理器获取到 pipeline.addLast(new IdleStateHandler(config.getApiPlatformMessage().getReadIdleTimeOut(),0, 0, TimeUnit.SECONDS)); // 心跳机制处理 pipeline.addLast(new HeartbeatTimeoutHandler()); //处理web socket协议与握手 pipeline.addLast(new WebSocketServerProtocolHandler("/webSocket")); //数据基本验证 pipeline.addLast(new ValidateMessageHandler()); //去重 pipeline.addLast(new DistinctMessageHandler()); //将文本按消息类型转换为请求消息或响应消息 pipeline.addLast(new MessageTypeDecodeHandler()); //请求消息业务逻辑处理器 pipeline.addLast(new RequestMessageBusinessHandler()); //响应消息业务逻辑处理器 pipeline.addLast(new ResponseMessageBusinessHandler()); //编码为TextWebSocketFrame pipeline.addLast(new TextWebSocketFrameEncodeHandler()); //json序列化 pipeline.addLast(new JsonEncodeHandler()); }
对于通道中装配的处理器,每次都是new出一个新实例来。如果我们的平台,有大量的客户端连接,实际还是会创建出多个对象实例出来。
这里我们可以考虑加一点优化,即定义1个实例,多个通道共享。
例如,对于基本的数据验证,改造成以下方式
//在类中自动注入 @Autowired private ValidateMessageHandler validateMessageHandler; //直接使用单例对象,而不是每次new一个出来 pipeline.addLast(validateMessageHandler);
做完以上这两步还不够,还需要在ValidateMessageHandler类上加上@Sharable注解。
netty会进行验证,如果没有注解则会报错。
这里有一点需要注意,多通道共享的处理器,必须是无状态的,因为要保证线程安全。
很明显,对于解码器,是有状态的,需要内置一些变量来保存接收到的部分数据,对于该类处理器,肯定是线程不安全的,是不能共享的。
一般来说,这里的改造,对性能提升并不明显,除非是建立了海量连接,并且重连会比较频繁,毕竟,为每个连接创建一套处理器的实例对象的开销并不大。
netty设计共享处理器,实际的应用场景在于跨通道进行收集信息用于统计。