這是最近在實際開發中遇到的一個問題,用 asp.net core 開發一個后端 web api ,根據指定的 key 清除 2 臺 memcached 服務器上的緩存。背景是我們在進行 .net core 遷移工作,asp.net 項目與 asp.net core 項目并存,為了避免兩種類型項目的緩存沖突,我們分別用了 2 臺不同的 memcached 服務器。
之前使用 1 臺 memcached 服務器時,只需要一個客戶端,所以只需創建一個 MemcachedClient 單例并注入到 IMemcachedClient 接口。
public void ConfigureServices(IServiceCollection services) { services.AddOptions(); services.Configure<MemcachedClientOptions>(Configuration.GetSection("memcached")); services.Add(ServiceDescriptor.Transient<IMemcachedClientConfiguration, MemcachedClientConfiguration>()); services.Add(ServiceDescriptor.Singleton<IMemcachedClient, MemcachedClient>()); }
(注:memcached 的配置存儲在 appsettings.json 中)
而現在需要用 2 個 memcached 客戶端實例分別連接 2 臺不同的 memcached 服務器,需要 2 個不同配置的 MemcachedClient 單例,而之前針對 1 個 IMemcachedClient 接口的依賴注入方法不管用了。咋整?
首先想到的是一個變通的方法,1 個接口不行,那就用 2 個接口,于是增加下面的 2 個接口:
public interface IMemcachedClientCore : IMemcachedClient {
} public interface IMemcachedClientLegacy : IMemcachedClient {
}
因為 MemcachedClient 并沒有實現這個這 2 個接口,還要另外增加這 2 個接口的實現:
public class MemcachedClientCore : MemcachedClient, IMemcachedClientCore { public MemcachedClientCore( ILogger<MemcachedClient> logger, IMemcachedClientConfiguration configuration) : base(logger, configuration) { } } public class MemcachedClientLegacy : MemcachedClient, IMemcachedClientLegacy { public MemcachedClientLegacy( ILogger<MemcachedClient> logger, IMemcachedClientConfiguration configuration) : base(logger, configuration) { } }
沿著這條路發現越走越不對勁,還要增加更多的接口與實現。由于 2 個 memcached 客戶端的不同在于 IMemcachedClientConfiguration 的不同,而上面的 MemcachedClientCore 與 MemcachedClientLegacy 的構造函數都注入 IMemcachedClientConfiguration 是不行的,還要基于 IMemcachedClientConfiguration 再增加 2 個接口,增加了接口就又不得不再增加實現。。。這樣解決問題豈不讓人瘋掉,遂棄之。
后來轉念一想,自己解決問題的思路走偏了,一味地將關注的焦點放在如何通過 Dependency Injection 注入 2 個不同的 MemcachedClient 實例,而忽略了一個很簡單的解決方法 —— 用工廠類創建 MemcachedClient 實例,通過 Dependency Injection 注入工廠類,就像 ILoggerFactory 那樣。
于是通過基于依賴注入的工廠模式輕松解決了這個問題。
定義一個 IMemcachedClientFactory 接口:
public interface { IMemcachedClientFactory Add(string keyOfConfiguration); IMemcachedClient Create(string keyOfConfiguration); }
添加 MemcachedClientFactory 類實現 IMemcachedClientFactory 接口:
public class MemcachedClientFactory : IMemcachedClientFactory { private readonly ILoggerFactory _loggerFactory; private readonly IConfiguration _configuration; private readonly Dictionary<string, IMemcachedClient> _clients = new Dictionary<string, IMemcachedClient>(); public MemcachedClientFactory( ILoggerFactory loggerFactory, IConfiguration configuration) { _loggerFactory = loggerFactory; _configuration = configuration; } public IMemcachedClientFactory Add(string keyOfConfiguration) { var options = new MemcachedClientOptions(); _configuration.GetSection(keyOfConfiguration).Bind(options); var memcachedClient = new MemcachedClient( _loggerFactory, new MemcachedClientConfiguration(_loggerFactory, options)); _clients.Add(keyOfConfiguration, memcachedClient); return this; } public IMemcachedClient Create(string keyOfConfiguration) { return _clients[keyOfConfiguration]; } }
在 Startup.ConfigureServices() 中注入 MemcachedClientFactory 的單例:
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IMemcachedClientFactory, MemcachedClientFactory>(); }
在 Startup.Configure() 中調用 IMemcachedClientFactory 接口的 Add() 方法,根據不同配置創建 MemcachedClient 的實例:
public void Configure(IApplicationBuilder app, IMemcachedClientFactory memcachedClientFactory) { memcachedClientFactory.Add("MemcachedLegacy").Add("MemcachedCore"); }
在使用 MemcachedClient 的地方通過 IMemcachedClientFactory 接口的 Create() 方法獲取所需 MemcachedClient 的實例:
public class CacheController : Controller { private readonly IMemcachedClient _memcachedClientLegacy; private readonly IMemcachedClient _memcachedClientCore; public CacheController(IMemcachedClientFactory memcachedClientFacotry) { _memcachedClientLegacy = memcachedClientFacotry.Create("MemcachedLegacy"); _memcachedClientCore = memcachedClientFacotry.Create("MemcachedCore"); } [HttpDelete("{key}")] public async Task<IActionResult> Delete(string key) { var removeCoreTask = _memcachedClientCore.RemoveAsync(key); var removeLegacyTask = _memcachedClientLegacy.RemoveAsync(key); await removeCoreTask; await removeLegacyTask; return Ok(); } }
文章列表