今天我们来做一个优化,即实现消息处理器的复用,注意这里的复用,不是指同一个消息处理器在消息的客户端和服务端进行复用,而是指在多个消息通道中复用。
回顾下我们消息处理器装配的过程,代码实现如下:
/**
* 初始化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设计共享处理器,实际的应用场景在于跨通道进行收集信息用于统计。