這是最近在實際開發中遇到的一個問題,用 asp.net core 開發一個後端 web api ,根據指定的 key 清除 2 臺 memcached 服務器上的緩存。背景是咱們在進行 .net core 遷移工做,asp.net 項目與 asp.net core 項目並存,爲了不兩種類型項目的緩存衝突,咱們分別用了 2 臺不一樣的 memcached 服務器。web
以前使用 1 臺 memcached 服務器時,只須要一個客戶端,因此只需建立一個 MemcachedClient 單例並注入到 IMemcachedClient 接口。json
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 接口的依賴注入方法無論用了。咋整?api
首先想到的是一個變通的方法,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 個接口,增長了接口就又不得再也不增長實現。。。這樣解決問題豈不讓人瘋掉,遂棄之。app
後來轉念一想,本身解決問題的思路走偏了,一味地將關注的焦點放在如何經過 Dependency Injection 注入 2 個不一樣的 MemcachedClient 實例,而忽略了一個很簡單的解決方法 —— 用工廠類建立 MemcachedClient 實例,經過 Dependency Injection 注入工廠類,就像 ILoggerFactory 那樣。asp.net
因而經過基於依賴注入的工廠模式輕鬆解決了這個問題。async
定義一個 IMemcachedClientFactory 接口:memcached
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 memcachedClientFactory) { _memcachedClientLegacy = memcachedClientFactory.Create("MemcachedLegacy"); _memcachedClientCore = memcachedClientFactory.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(); } }