Azure Service Bus:兼顾复用与动态创建ServiceBusSender处理请求回复
解决Service Bus动态回复队列与Sender复用的矛盾
在依赖注入场景下,要兼顾动态回复不同队列和官方建议的Sender复用要求,可通过以下方案实现:
1. 基于单例ServiceBusClient的Sender缓存工厂
核心思路是复用单例的ServiceBusClient,同时缓存根据不同队列创建的ServiceBusSender,避免重复创建Sender实例。
实现步骤:
- 将
ServiceBusClient注册为单例注入DI容器 - 创建单例的Sender工厂类,内部用线程安全字典缓存已创建的Sender
- 业务逻辑通过工厂类获取对应队列的Sender,工厂自动处理创建与复用
代码示例:
// Sender工厂类 public class ServiceBusSenderFactory { private readonly ServiceBusClient _serviceBusClient; private readonly ConcurrentDictionary<string, ServiceBusSender> _senderCache = new(); public ServiceBusSenderFactory(ServiceBusClient serviceBusClient) { _serviceBusClient = serviceBusClient; } public ServiceBusSender GetSender(string queueOrTopicName) { // 不存在则创建并缓存,存在则直接返回 return _senderCache.GetOrAdd(queueOrTopicName, _serviceBusClient.CreateSender); } } // DI注册 services.AddSingleton<ServiceBusClient>(sp => new ServiceBusClient(Configuration.GetConnectionString("AzureServiceBus"))); services.AddSingleton<ServiceBusSenderFactory>(); // 业务处理类中使用 public class ServiceAMessageHandler { private readonly ServiceBusSenderFactory _senderFactory; public ServiceAMessageHandler(ServiceBusSenderFactory senderFactory) { _senderFactory = senderFactory; } public async Task ProcessMessageAsync(ServiceBusReceivedMessage message, CancellationToken cancellationToken) { var replyQueue = message.ReplyTo; if (string.IsNullOrEmpty(replyQueue)) { // 无回复地址,无需处理 return; } // 获取对应队列的Sender var replySender = _senderFactory.GetSender(replyQueue); // 构造回复消息 var replyMessage = new ServiceBusMessage("处理完成") { CorrelationId = message.MessageId }; await replySender.SendMessageAsync(replyMessage, cancellationToken); } }
2. 理解官方建议的核心边界
官方强调不要频繁创建ServiceBusClient,而非完全禁止创建ServiceBusSender。从单例Client创建Sender的开销极低,远低于创建Client的成本。只要复用Client,即使偶尔创建新Sender,也不会对性能造成明显影响,配合缓存则能进一步优化资源使用。
3. 可选:临时Sender的生命周期管理
若存在大量临时回复队列(极少场景),可在工厂中添加缓存清理逻辑,定期移除长时间未使用的Sender。但大部分业务场景下,服务的回复队列是固定的,无需额外清理。
内容的提问来源于stack exchange,提问作者Joerg
相关产品推荐
相关产品推荐

